BZOJ2125: 最短路(圆方树)
时间:2022-06-17
本文章向大家介绍BZOJ2125: 最短路(圆方树),主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。
Time Limit: 1 Sec Memory Limit: 259 MB
Submit: 1574 Solved: 651
Description
给一个N个点M条边的连通无向图,满足每条边最多属于一个环,有Q组询问,每次询问两点之间的最短路径。
Input
输入的第一行包含三个整数,分别表示N和M和Q 下接M行,每行三个整数v,u,w表示一条无向边v-u,长度为w 最后Q行,每行两个整数v,u表示一组询问
Output
输出Q行,每行一个整数表示询问的答案
Sample Input
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
Sample Output
5 6
HINT
对于100%的数据,N<=10000,Q<=10000
Source
圆方树好毒瘤神奇啊qwq。
对于这题来说的话,首先把圆方树弄出来
考虑询问的两个点,如果他们的lca是圆点,那么直接树上前缀和相加
如果不是圆点,那么他们的lca一定是在一个环内,
我们可以维护出环内任意一点到环的根节点(也就是$dfn$最小的节点)的最短路径
然后分类讨论一下即可
对于一个点如何跳的它lca所在的环上,这里有个骚操作。
我们考虑树链剖分的过程
如果这个节点是重儿子,因为重儿子的dfs序是与父节点连续的,所以要求的点就是lca的dfs中对应的下一个节点
如果不是重儿子,那么我们一直跳,直到跳到lca处位置,那么要求的点就是来时离lca最近的那个节点
#include<cstdio>
#include<vector>
#include<cstring>
using namespace std;
const int MAXN = 1e6 + 10;
inline int read() {
char c = getchar(); int x = 0, f = 1;
while(c < '0' || c > '9') {if(c == '-') f = -1; c = getchar();}
while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
return x * f;
}
int N, M, Q;
struct Edge {
int u, v, w, nxt;
}E[MAXN];
int head[MAXN], num = 1;
inline void AddEdge(int x, int y, int z) {
E[num] = (Edge){x, y, z, head[x]};
head[x] = num++;
}
vector<Edge> vec[MAXN];
inline void add_edge(int x, int y, int z) {
vec[x].push_back((Edge){x, y, z});
vec[y].push_back((Edge){y, x, z});
}
int low[MAXN], dfn[MAXN], times, fa[MAXN], cdis[MAXN], dis[MAXN], tot;
inline void Build(int x, int y, int w) {
for(int i = y; i != x; i = fa[i]) cdis[i] = w, w += dis[i];
cdis[++tot] = w; add_edge(tot, x, 0);//建方点
for(int i = y; i != x; i = fa[i]) add_edge(tot, i, min(cdis[i], w - cdis[i]));
}
void Tarjan(int x, int _fa) {
dfn[x] = low[x] = ++times; fa[x] = _fa;
for(int v, i = head[x]; i != -1; i = E[i].nxt) {
if((v = E[i].v) == _fa) continue;
if(!dfn[v]) dis[v] = E[i].w, Tarjan(v, x), low[x] = min(low[x], low[v]);
else low[x] = min(low[x], dfn[v]);
if(low[v] > dfn[x]) add_edge(x, v, E[i].w);
}
// can I take this into for ?
for(int v, i = head[x]; i != -1; i = E[i].nxt)
if(fa[(v = E[i].v)] != x && dfn[v] > dfn[x])//如果不是负边,那么一定出现了环
Build(x, v, E[i].w);
}
int siz[MAXN], son[MAXN], top[MAXN], deep[MAXN], Index = 0, point[MAXN];
void dfs1(int x, int _fa) {
fa[x] = _fa; siz[x] = 1;
for(int i = 0, v; i < vec[x].size(); i++) {
if((v = vec[x][i].v) == _fa) continue;
dis[v] = dis[x] + vec[x][i].w;
deep[v] = deep[x] + 1;
dfs1(v, x);
siz[x] += siz[v];
if(siz[v] > siz[son[x]]) son[x] = v;
}
}
void dfs2(int x, int topf) {
top[x] = topf; point[dfn[x] = ++Index] = x;
if(!son[x]) return ;
dfs2(son[x], topf);
for(int i = 0, v; i < vec[x].size(); i++)
if(!top[v = vec[x][i].v])
dfs2(v, v);
}
int LCA(int x, int y) {
while(top[x] != top[y]) {
if(deep[top[x]] < deep[top[y]]) swap(x, y);
x = fa[top[x]];
}
if(deep[x] < deep[y]) swap(x, y);
return y;
}
int Jump(int x, int lca) {
int las;
while(top[x] != top[lca]) las = top[x], x = fa[top[x]];//las = top[x] not x
return x == lca ? las : point[dfn[lca] + 1];//这里要写lca
}
int abs(int x) {
return x < 0 ? -x : x;
}
int main() {
#ifdef WIN32
freopen("a.in", "r", stdin);
freopen("a.out", "w", stdout);
#endif
tot = N = read(); M = read(); Q = read();
memset(head, -1, sizeof(head));
for(int i = 1; i <= M; i++) {
int x = read(), y = read(), z = read();
AddEdge(x, y, z); AddEdge(y, x, z);
}
Tarjan(1, 0); dis[1] = 0; deep[1] = 1;
//for(int i = 1; i <= N; i++) printf("%d ", dfn[i]); puts("");
//for(int i = 1; i <= N; i++) printf("%d ", vec[i].size()); puts("");
//printf("%dn", tot);
dfs1(1, 0);
dfs2(1, 1);
//for(int i = 1; i <= tot; i++) printf("%d ", top[i]); puts("");
while(Q--) {
int x = read(), y = read();
int lca = LCA(x, y);
if(lca <= N) {printf("%dn", dis[x] + dis[y] - (dis[lca] << 1)); continue;}
int p1 = Jump(x, lca);
int p2 = Jump(y, lca);
int ans = dis[x] - dis[p1] + dis[y] - dis[p2] + min(abs(cdis[p2] - cdis[p1]),
cdis[lca] - abs(cdis[p2] - cdis[p1]));
printf("%dn", ans);
}
return 0;
}
- .NET Core系列 : 2 、project.json 这葫芦里卖的什么药
- 关闭与恢复visual studio实时调试器
- linux系统下的权限知识梳理
- c#如何启动/干掉/查找 进程
- Android中Application的应用
- 孟昭莉博士:大数据大道之行
- .NET Core系列 :3 、使用多个项目
- 完整部署CentOS7.2+OpenStack+kvm 云平台环境(2)--云硬盘等后续配置
- 完整部署CentOS7.2+OpenStack+kvm 云平台环境(3)--为虚拟机指定固定ip
- ubuntu系统升级记录
- .NET Core系列 :4 测试
- 完整部署CentOS7.2+OpenStack+kvm 云平台环境(4)--用OZ工具制作openstack镜像
- centos下部署NTP时间服务器同步环境记录
- ASP.NET MVC扩展库
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- Array - 295. Find Median from Data Stream
- Array - 239. Sliding Window Maximum
- Array - 164. Maximum Gap
- Array - 128. Longest Consecutive Sequence
- String - 13. Roman to Integer
- String - 171. Excel Sheet Column Number
- String - 168. Excel Sheet Column Title
- String - 316. Remove Duplicate Letters
- String - 38. Count and Say
- String - 161. One Edit Distance
- String - 6. ZigZag Conversion
- String - 179. Largest Number
- 利用Github Pages实现“服务CNAME”功能
- String - 49. Group Anagrams
- Flutter包大小治理上的探索与实践