【图论】【模板】静态仙人掌(luogu 5236)

【模板】静态仙人掌

题目大意

给你一个无向仙人掌图(保证每条边至多出现在一个简单回路中的无向图),问你两个点之间的最短路距离

输入样例#1

9 10 2
1 2 1
1 4 1
3 4 1
2 3 1
3 7 1
7 8 2
7 9 2
1 5 3
1 6 4
5 6 1
1 9
5 7

输出样例#1

5
6

输入样例#2

9 10 3
1 2 1
2 3 1
2 4 4
3 4 2
4 5 1
5 6 1
6 7 2
7 8 2
8 9 4
5 9 2
1 9
5 8
3 4

输出样例#2

7
5
2

样例解释:

样例1中的仙人掌是这个样子的:
在这里插入图片描述

询问有两个,分别是询问 1→\rightarrow 9和 5→\rightarrow 7的最短路
显然答案分别为 5 和 6。

数据范围:

1≤n,q≤100001\le n,q \le 100001n,q10000
1≤m≤200001\le m \le 200001m20000
1≤w≤1051\le w \le 10^51w105
请注意时限为 300ms300\text{ms}300ms

解题思路

我们把该图转化为圆方树
建树规则:
1:对于不在环里面的边,我们保留不变
2:对于环,我们建一个方点(黄色的点),连接这个该环上所有点,边权为为所有点到dfsdfsdfs序最小的点的距离(如图)
搜索的时候,我们记录下某个点的dfsdfsdfs序,以及从这个点出发走到的点中dfsdfsdfs序最小的点的dfsdfsdfs序(父亲边除外)
当我们搜到某个点时,枚举到某条边(如图红色的边),若该边指向的点已经搜过,且父亲节点不是该点,且dfs序大于该点,那么我们搜到了一个环,且这个环中dfsdfsdfs序最小的点就是该点
dfsdfsdfs序大于该点,很显然是该点出发搜索到的点
且与该点相连,那么肯定是一个环了
从该点出发,一边是从该点搜索到的点,且dfs序逐渐变大,dfsdfsdfs序大于该点,另一边是红色边的点,dfsdfsdfs序也大于该点
那么该点就是该环所有点中dfsdfsdfs序最小的点
在这里插入图片描述
我们像这样建树
然后得到了一棵圆方数
对于树上两点的最短距离
就是两点到lcalcalca的距离
lcalcalca不是方点,但经过方点,那经过该环的距离就是走到dfsdfsdfs序最小的点最短的距离,也就是从该环中某个圆点到方点再到dfsdfsdfs序最小的点的距离,所以没有影响

对于lcalcalca是方点的,我们先计算到该环某个圆点的距离,然后求到对方点的最小距离即可(就是两个方向距离的minminmin

代码

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define ll long long
using namespace std;
ll n, m, w, x, y, z, q, X, Y, ex, ans, tot, tott, b[100010], fa[200010], dep[200010], dis[200010], sum[200010], dfn[200010], low[200010], h[200010], head[200010], f[200010][20];
struct rec
{ll to, l, next;
}e[2000010], a[2000010];
int read()//快读
{char x=getchar();int d=1,l=0;while (x<'0'||x>'9') {if (x=='-') d=-1;x=getchar();}while (x>='0'&&x<='9') l=(l<<3)+(l<<1)+x-48,x=getchar();return l*d;
}
void writ(int c) {if (c>9) writ(c/10); putchar(c%10+48); return;}
void write(int s) {s<0?putchar(45),writ(-s):writ(s); putchar(10); return;}
void add(ll x, ll y, ll z)//加圆方树的边
{a[++tot].to = y;a[tot].l = z;a[tot].next = head[x];head[x] = tot;a[++tot].to = x;a[tot].l = z;a[tot].next = head[y];head[y] = tot;
}
void addd(ll x, ll y, ll z)//加原图的边
{e[++tott].to = y;e[tott].l = z;e[tott].next = h[x];h[x] = tott;e[++tott].to = x;e[tott].l = z;e[tott].next = h[y];h[y] = tott;
}
void jh(ll x, ll y, ll z)//对于环,建圆方树
{++ex;ll pt = y, ss = z;while(pt != fa[x])//求从x到所有点走反边的距离(红色边的方向){sum[pt] = ss;ss += b[pt];//求和pt = fa[pt];}sum[ex] = sum[x];sum[x] = 0;pt = y;ss = 0;while(pt != fa[x]){ss = min(sum[pt], sum[ex] - sum[pt]);//走两条边中最短的add(pt, ex, ss);//加边pt = fa[pt];}
}
void dfs(ll x)
{dfn[x] = low[x] = ++w;for (int i = h[x]; i; i = e[i].next)if (e[i].to != fa[x]) {ll v = e[i].to;if (!dfn[v])//没走过{fa[v] = x;b[v] = e[i].l;//记录dfs(v);low[x] = min(low[x], low[v]);//记录由该点走出去的点中dfs序最小的}else low[x] = min(low[x], dfn[v]);//到过了,要不就是走回了变if (low[v] > dfn[x]) add(x, v, e[i].l);}for (int i = h[x]; i; i = e[i].next)if ( dfn[e[i].to] > dfn[x] && fa[e[i].to] != x)jh(x, e[i].to, e[i].l);
}
void dfs1(int x)
{dep[x] = dep[f[x][0]] + 1;for (int j = 1; j <= 16; ++j)f[x][j] = f[f[x][j - 1]][j - 1];//倍增for (int i = head[x]; i; i = a[i].next)if (a[i].to != f[x][0]){f[a[i].to][0] = x;if (dis[a[i].to]) dis[a[i].to] = min(dis[a[i].to], dis[x] + a[i].l);else dis[a[i].to] = dis[x] + a[i].l;dfs1(a[i].to);}
}
ll lca(ll x, ll y)
{if (dep[x] < dep[y]) swap(x, y);//求lcafor (int i = 16; i >= 0; --i)if (dep[f[x][i]] >= dep[y]) x = f[x][i];for (int i = 16; i >= 0; --i)if (f[x][i] != f[y][i]) x = f[x][i], y = f[y][i];X = x;//若两点不是祖先关系,那会停留在前一个点Y = y;return x == y?x:f[x][0];
}
int main()
{n = read();m = read();q = read();ex = n;for (int i = 1; i <= m; ++i){x = read();y = read();z = read();addd(x, y, z);}dfs(1);f[1][0] = 1;dfs1(1);for (int i = 1; i <= q; ++i){x = read();y = read();z = lca(x, y);if (z <= n) ans = dis[x] + dis[y] - dis[z] - dis[z];//lca是圆点else{ans = dis[x] - dis[X] + dis[y] - dis[Y]; //到环上两圆点的距离if (sum[X] > sum[Y]) swap(X, Y);ans += min(sum[Y] - sum[X], sum[z] - sum[Y] + sum[X]);//环的两个方向}write(ans);}return 0;
} 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/320171.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Wannafly挑战赛24D-无限手套【dp,生成函数】

正题 题目链接:https://ac.nowcoder.com/acm/contest/186/D 题目大意 mmm个二元组(ai,bi)(a_i,b_i)(ai​,bi​)&#xff0c;对于一个序列xxx的贡献是∏i1n(aixi2bixi1)\prod_{i1}^n(a_ix_i^2b_ix_i1)i1∏n​(ai​xi2​bi​xi​1) qqq次询问给出nnn求在xi≥0x_i\geq 0xi​≥0且…

SCF: 简单配置门面

Simple Configuration Facade, 简写为 SCF。是 代码 和 外部配置 (properties文件, 环境变量&#xff0c;系统/命令行参数, yaml文件, 等等)之间的一层抽象. 命名上和另一个著名组件slf4j (Simple Logging Facade for Java)相似, 在配置领域的地位也和slf4j &#xff08;.NET可…

字符串(AC自动机(fail tree))

传送门 注意&#xff1a;注释中的那段代码是不能用的 #include<iostream> #include<cstdio> #include<cstring> #include<cmath> #include<queue> using namespace std; typedef long long ll; const int N2000010; struct Edge{int v,nxt;}ed…

武汉工程大学2020GPLT选拔赛(上)

比赛链接 A L1-1 I LOVE WIT 模拟&#xff0c;每个字母单独一行&#xff0c;前面的空格按规律输出。可以直接输出&#xff0c;也可以模拟过程 #include<bits/stdc.h> using namespace std; int main(){string s"I LOVE WIT";for(int i0;i<s.size();i){fo…

【矩阵乘法】【倍增】美食家(luogu 6772)

美食家 题目大意 给你一个有向图&#xff0c;边权为经过所需时间 每个点有一个点权&#xff0c;有些点还有有特殊的点权 当你到达一个点后&#xff0c;可以获得该点的点权&#xff08;重复经过可以重复获得&#xff0c;但不能停留&#xff09;&#xff0c;若在某个时间到某个…

.net core实践系列之短信服务-为什么选择.net core(开篇)

前言从今天我将会写.net core实战系列&#xff0c;以我最近完成的短信服务作为例子。该系列将会尽量以最短的时间全部发布出来。源码也将优先开源出来给大家。源码地址&#xff1a;https://github.com/SkyChenSky/Sikiro.SMS.NET CORE简介ASP.NET Core 是一个跨平台的高性能开源…

P3172-[CQOI2015]选数【dp,容斥】

正题 题目链接:https://www.luogu.com.cn/problem/P3172 题目大意 求有多少个长度为NNN的值域在[L,R][L,R][L,R]这个区间的序列满足它们的gcdgcdgcd恰好是KKK。 解题思路 dpdpdp容斥思想 我们先让L⌊LK−1K⌋,R⌊RK⌋L\lfloor\frac{LK-1}{K}\rfloor,R\lfloor\frac{R}{K}\rfl…

博弈论总结

前言 本篇为博弈论总结&#xff0c;文章会按题目类型分类。 基础铺垫——必胜点和必败点的介绍 P点&#xff1a;必败点&#xff0c;换而言之&#xff0c;就是谁处于此位置&#xff0c;则在双方操作正确的情况下必败。 N点&#xff1a;必胜点&#xff0c;处于此情况下&#x…

牛客网【每日一题】5月8日题目精讲 codeJan与旅行

比赛链接&#xff1a; 文章目录题目描述题解&#xff1a;时间限制&#xff1a;C/C 1秒&#xff0c;其他语言2秒 空间限制&#xff1a;C/C 262144K&#xff0c;其他语言524288K 64bit IO Format: %lld题目描述 codeJan 非常喜欢旅行。现在有 n 个城市排在一条线上&#xff0c;并…

.netcore consul实现服务注册与发现-集群完整版

一、Consul的集群介绍Consul Agent有两种运行模式&#xff1a;Server和Client。这里的Server和Client只是Consul集群层面的区分&#xff0c;与搭建在Cluster之上的应用服务无关&#xff0c; 以Server模式运行的Consul Agent节点用于维护Consul集群的状态&#xff0c;官方建议每…

【矩阵乘法】【倍增】WYC(luogu 3597)

WYC 题目大意 给你一个有向图&#xff0c;让你求图中的kkk短路&#xff08;非简单路径&#xff09; 输入样例# 6 6 11 1 2 1 2 3 2 3 4 2 4 5 1 5 3 1 4 6 3输出样例#1 4数据范围 1⩽n⩽40&#xff0c;1⩽m⩽1000&#xff0c;1⩽k⩽10181\leqslant n\leqslant 40&#xff…

匹配(树形DP)

传送门 题目描述&#xff1a; 有一张无向联通图 G⟨V,E⟩ &#xff0c;其中顶点数 |V|n &#xff0c;边数 |E|n−1 。求有多少种方案使得删边后残余图中的最大匹配数恰好为 m 的倍数。 题解&#xff1a; 这道题看起来是求最大匹配&#xff0c;其实关系不大&#xff0c;正解…

博弈论讲解(一)

常见的博弈论有巴什博弈&#xff0c;威佐夫博弈&#xff0c;尼姆博弈&#xff0c;斐波那契博弈等等&#xff0c;今天暂时讲几个 文章目录一.巴什博弈证明&#xff1a;代码二.威佐夫博奕结论&#xff1a;代码&#xff1a;三.环形博弈结论证明代码&#xff1a;一.巴什博弈 巴什博…

浅谈surging服务引擎中的rabbitmq组件和容器化部署

1、前言上个星期完成了surging 的0.9.0.1 更新工作&#xff0c;此版本通过nuget下载引擎组件&#xff0c;下载后&#xff0c;无需通过代码build集成&#xff0c;引擎会通过Sidecar模式自动扫描装配异构组件来构建服务引擎&#xff0c;而这篇将介绍浅谈surging服务引擎中的rabbi…

csp-j/s总结

文章目录csp-jcsp-s总结csp-j T1傻逼题(我是傻逼&#xff09;&#xff0c;手残把&打成整除了&#xff08;大样例还对了gg&#xff09; T2乱推&#xff0c;然后打了个O(n)O(n)O(n)&#xff0c;却WA了15分&#xff1f; T3看了看&#xff0c;修改不会相互影响&#xff1f;那不…

51nod1220-约数之和【莫比乌斯反演,杜教筛】

正题 题目链接:http://www.51nod.com/Challenge/Problem.html#problemId1220 题目大意 给出nnn&#xff0c;求∑i1n∑j1nσ(i∗j)\sum_{i1}^n\sum_{j1}^n\sigma(i*j)i1∑n​j1∑n​σ(i∗j) 其中σ\sigmaσ表示约数和。 解题思路 首先有结论σ(i∗j)∑x∣i∑y∣j[gcd(x,y)1]…

CDQ分治与整体二分

首先说明&#xff0c;CDQ分治与整体二分都是离线算法 CDQ分治&#xff1a; 流程&#xff1a; 1.我们要解决一系列问题&#xff0c;这些问题一般包含修改和查询操作&#xff0c;可以把这些问题排成一个序列&#xff0c;用一个区间[L,R]表示。 2.分。递归处理左边区间[L,M]和…

博弈论讲解(二)

文章目录斐波那契博弈问题&#xff1a;结论证明&#xff1a;尼姆博奕(Nimm Game)问题&#xff1a;结论&#xff1a;证明&#xff1a;代码&#xff1a;公平组合博弈&#xff08;Impartial Combinatori Games&#xff09;理论知识&#xff08;1&#xff09;、若面临末状态者为获胜…

.net core实践系列之短信服务-架构设计

前言上篇《.net core实践系列之短信服务-为什么选择.net core&#xff08;开篇&#xff09;》简单的介绍了&#xff08;水了一篇&#xff09;.net core。这次针对短信服务的架构设计和技术栈的简析。源码地址&#xff1a;https://github.com/SkyChenSky/Sikiro.SMS为什么需要架…

【矩阵乘法】Matrix Power Series(poj 3233)

Matrix Power Series poj 3233 题目大意 给你一个矩阵A&#xff0c;让你求SAA2A3…AkS A A^2 A^3 … A^kSAA2A3…Ak 输入样例 2 2 4 0 1 1 1输出样例 1 2 2 3n⩽30,k⩽109,m<104,a∈A,a⩽32768n \leqslant 30,k \leqslant 10^9,m < 10^4,a\in A,a \leqslant32…