【BZOJ】2125: 最短路 圆方树(静态仙人掌)
【题意】给定带边权仙人掌图,Q次询问两点间最短距离。n,m,Q<=10000
【算法】圆方树处理仙人掌问题
【题解】树上的两点间最短路问题,常用倍增求LCA解决,考虑扩展到仙人掌图。
先对仙人掌图建圆方树,圆圆边和原图边权一致。对于每个方点代表的环,记深度最小的点为x,则圆方边的边权是圆点到x的最短距离。
若lca(u,v)为圆点,则两点间最短路转化为圆方树上dis[u]+dis[v]-2*dis[lca]。(向上延伸的路径,经过环则必然经过每个方点的x,计算无误)
若lca(u,v)为方点,则记u,v在方点连接的圆点A,B的子树内,那么两点间最短路为dis[u]+dis[v]-dis[A]-dis[B]+dis(A,B),dis(A,B)是A,B在环上的短侧路径。
复杂度O(Q log n)。
实现细节:
1.Tarjan:建圆方树(先处理树边,最后在深度最小处处理环)
2.处理方点:s[i]表示点i从所在环点x(深度最小)开始逆时针的距离,最终s[x]记为s[N]后s[x]=0。另外注意要记录一下环中点的编号顺序。
3.LCA:圆点直接计算,方点中dis(A,B)=min{ s[A]+s[w]-s[B] , s[B]-s[A] }(A在B的顺时针方向,否则交换AB)。
4.注意防止访问父亲的边是i^1,初始tot=1。
#include<cstdio>
#include<cstring>
#include<algorithm>
#define ll long long
using namespace std;
const int maxn=;
int N,fa[maxn],b[maxn],f[maxn][],dfn[maxn],low[maxn],dfsnum=,deep[maxn],A,B,n,m,id[maxn];
ll s[maxn],dis[maxn];
struct tu{
int first[maxn],tot;
struct edge{int v,w,from;}e[maxn*];
void insert(int u,int v,int w){
tot++;e[tot].v=v;e[tot].w=w;e[tot].from=first[u];first[u]=tot;
tot++;e[tot].v=u;e[tot].w=w;e[tot].from=first[v];first[v]=tot;
}
}G;
int first[maxn],tot;
struct edge{int v,w,from;}e[maxn*];
void insert(int u,int v,int w){
tot++;e[tot].v=v;e[tot].w=w;e[tot].from=first[u];first[u]=tot;
tot++;e[tot].v=u;e[tot].w=w;e[tot].from=first[v];first[v]=tot;
}
void solve(int u,int v,int w){
N++;
int pre=w,ID=;
for(int i=v;i!=fa[u];i=fa[i]){
s[i]=pre;
pre+=b[i];
id[i]=ID++;
}
s[N]=s[u];s[u]=;
for(int i=v;i!=fa[u];i=fa[i])insert(N,i,min(s[i],s[N]-s[i]));
}
void tarjan(int x,int father){
dfn[x]=low[x]=++dfsnum;
for(int i=G.first[x];i;i=G.e[i].from)if(i!=father){
int y=G.e[i].v;
if(!dfn[y]){
fa[y]=x;b[y]=G.e[i].w;
tarjan(G.e[i].v,i^);
low[x]=min(low[x],low[y]);
}else low[x]=min(low[x],dfn[y]);
if(low[y]>dfn[x])insert(x,y,G.e[i].w);
}
for(int i=G.first[x];i;i=G.e[i].from){
int y=G.e[i].v;
if(fa[y]!=x&&dfn[y]>dfn[x])solve(x,y,G.e[i].w);
}
}
void dfs(int x,int father){
for(int j=;(<<j)<=deep[x];j++)f[x][j]=f[f[x][j-]][j-];
for(int i=first[x];i;i=e[i].from)if(i!=father){
f[e[i].v][]=x;
deep[e[i].v]=deep[x]+;
dis[e[i].v]=dis[x]+e[i].w;
dfs(e[i].v,i^);
}
}
int lca(int x,int y){
if(deep[x]<deep[y])swap(x,y);
int d=deep[x]-deep[y];
for(int i=;(<<i)<=d;i++)if(d&(<<i))x=f[x][i];
if(x==y)return x;
for(int i=;i>=;i--)if((<<i)<=deep[x]&&f[x][i]!=f[y][i]){
x=f[x][i];y=f[y][i];
}
A=x;B=y;
return f[x][];
} int main(){
int Q;
scanf("%d%d%d",&n,&m,&Q);
int u,v,w;
G.tot=;tot=;
for(int i=;i<=m;i++){
scanf("%d%d%d",&u,&v,&w);
G.insert(u,v,w);
}
N=n;tarjan(,);dfs(,);
while(Q--){
scanf("%d%d",&u,&v);
w=lca(u,v);
if(w<=n)printf("%lld\n",dis[u]+dis[v]-*dis[w]);
else{
ll ans=dis[u]+dis[v]-dis[A]-dis[B];
if(id[A]<id[B])ans+=min(s[A]+s[w]-s[B],s[B]-s[A]);
else ans+=min(s[B]+s[w]-s[A],s[A]-s[B]);
printf("%lld\n",ans);
}
}
return ;
}
【BZOJ】2125: 最短路 圆方树(静态仙人掌)的更多相关文章
- 图论杂项细节梳理&模板(虚树,圆方树,仙人掌,欧拉路径,还有。。。)
orzYCB 虚树 %自为风月马前卒巨佬% 用于优化一类树形DP问题. 当状态转移只和树中的某些关键点有关的时候,我们把这些点和它们两两之间的LCA弄出来,以点的祖孙关系连成一棵新的树,这就是虚树. ...
- BZOJ2125 最短路 圆方树、倍增
传送门 对仙人掌建立圆方树,然后对边定权 对于圆点和圆点之间的边,是原来仙人掌上的桥,边权保持不变 对于圆点和方点之间的边,将圆方树看做以一个圆点为根的有根树之后,一个方点的父亲一定是一个圆点.对于这 ...
- [BZOJ2125]最短路(圆方树DP)
题意:仙人掌图最短路. 算法:圆方树DP,$O(n\log n+Q\log n)$ 首先建出仙人掌圆方树(与点双圆方树的区别在于直接连割边,也就是存在圆圆边),然后考虑点u-v的最短路径,显然就是:在 ...
- [BZOJ2125]最短路[圆方树]
题意 给定仙人掌,多次询问两点之间的最短路径. \(n\le 10000, Q\le 10000\) 分析 建出圆方树,分路径 lca 是圆点还是方点讨论. 预处理出根圆点到每个圆点的最短距离 \( ...
- 圆方树总结 [uoj30]Tourists
圆方树总结 所谓圆方树就是把一张图变成一棵树. 怎么变啊qaq 这里盗一张图 简单来说就是给每一个点双新建一个点,然后连向这个点双中的每一个点.特殊的,把两个点互相连通的也视作一个点双. 我们把原来就 ...
- bzoj 2125 最短路 点双 圆方树
LINK:最短路 一张仙人掌图 求图中两点最短路. \(n<=10000,Q<=10000,w>=1\) 考虑边数是多少 m>=n-1 对于一张仙人掌图 考虑先构建出来dfs树 ...
- BZOJ.2125.最短路(仙人掌 圆方树)
题目链接 圆方树.做题思路不写了.. 就是当LCA是方点时跳进那个环可以分类讨论一下用树剖而不必须用倍增: 如果v是u的(唯一的那个)重儿子,那么u的DFS序上+1的点即是要找的:否则v会引出一条新的 ...
- 【BZOJ2125】最短路(仙人掌,圆方树)
[BZOJ2125]最短路(仙人掌,圆方树) 题面 BZOJ 求仙人掌上两点间的最短路 题解 终于要构建圆方树啦 首先构建出圆方树,因为是仙人掌,和一般图可以稍微的不一样 直接\(tarjan\)缩点 ...
- 2018.07.25 bzoj2125: 最短路(圆方树+倍增)
传送门 人生的第一道仙人掌. 这道题求是仙人掌上的最短路. 先建出圆方树,然后用倍增跑最短路,当lca" role="presentation" style=" ...
随机推荐
- find . -name file -exec echo abc > {} \; fail
find . -name file -exec echo abc > {} \; fail 应该改用: find . -name file -exec bash -c 'echo abc > ...
- 1014C程序语法树
程序:冒泡算法C程序 #include <stdio.h> main() { int i,j,temp; int a[10]; for(i=0;i<10;i++) scanf (&q ...
- 高性能的HTTP代理 LittleProxy
引用: https://github.com/adamfisk/LittleProxy 拦截和操纵HTTPS流量,LittleProxy使用中间人(MITM)管理器. LittleProxy的默认实现 ...
- (转)Linux 命令--查看物理CPU个数、核数、逻辑CPU个数
# 总核数 = 物理CPU个数 X 每颗物理CPU的核数 # 总逻辑CPU数 = 物理CPU个数 X 每颗物理CPU的核数 X 超线程数 # 查看物理CPU个数 cat /proc/cpuinfo| ...
- 如何在java中实现跨线程的通讯
一般而言,如果没有干预的话,线程在启动之后会一直运行到结束,但有时候我们又需要很多线程来共同完成一个任务,这就牵扯到线程间的通讯. 如何让两个线程先后执行?Thread.join方法 private ...
- PHP实现HTML页面静态化
随着网站的内容的增多和用户访问量的增多,无可避免的是网站加载会越来越慢,受限于带宽和服务器同一时间的请求次数的限制,我们往往需要在此时对我们的网站进行代码优化和服务器配置的优化.一般情况下会从以下方面 ...
- 学习websocket-SignalR,MVC中使用SignalR打造酷炫实用的即时通讯
http://www.cnblogs.com/Leo_wl/p/4793284.html http://www.fangsi.net/archives/1144.html
- 【.Net】win10 uwp unix timestamp 时间戳 转 DateTime
有时候需要把网络的 unix timestamp 转为 C# 的 DateTime ,在 UWP 可以如何转换? 转换函数可以使用下面的代码 private static DateTime UnixT ...
- BZOJ 2004 公交线路(状压DP+矩阵快速幂)
注意到每个路线相邻车站的距离不超过K,也就是说我们可以对连续K个车站的状态进行状压. 然后状压DP一下,用矩阵快速幂加速运算即可. #include <stdio.h> #include ...
- 【bzoj2669】[cqoi2012]局部极小值 容斥原理+状压dp
题目描述 有一个n行m列的整数矩阵,其中1到nm之间的每个整数恰好出现一次.如果一个格子比所有相邻格子(相邻是指有公共边或公共顶点)都小,我们说这个格子是局部极小值. 给出所有局部极小值的位置,你的任 ...