[bzoj2125] 最短路
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
Solution
无脑建圆方树,大力出奇迹。
圆点和圆点的边权就直接是原图上的边权;
圆点和方点的边权设为圆点和这个环上\(dep\)最小的点的最短距离。
对于两个点\((x,y)\),设他们在圆方树上的\(lca\)为\(t\),若\(t\)是圆点,就直接树上距离就好了。
否则, 少跳一步,先跳掉离方点最近的两个圆点,然后在原图上求环上最小距离就好了。
(萌新刚学OI,代码写的很丑,不要介意)
#include<bits/stdc++.h>
using namespace std;
void read(int &x) {
x=0;int f=1;char ch=getchar();
for(;!isdigit(ch);ch=getchar()) if(ch=='-') f=-f;
for(;isdigit(ch);ch=getchar()) x=x*10+ch-'0';x*=f;
}
void print(int x) {
if(x<0) putchar('-'),x=-x;
if(!x) return ;print(x/10),putchar(x%10+48);
}
void write(int x) {if(!x) putchar('0');else print(x);putchar('\n');}
const int maxn = 2e5+10;
int n,m,q,cnt;
int head[maxn],tot=1,dfn[maxn],dfn_cnt,f[maxn],mark[maxn],fr[maxn],bel[maxn],dis[maxn];
struct edge{int to,nxt,w;}e[maxn<<1];
void add(int u,int v,int w) {e[++tot]=(edge){v,head[u],w},head[u]=tot;}
void ins(int u,int v,int w) {add(u,v,w),add(v,u,w);}
int st[maxn],ed[maxn],val[maxn];
void dfs(int x,int fa) {
dfn[x]=++dfn_cnt,f[x]=fa;
for(int i=head[x];i;i=e[i].nxt)
if(e[i].to!=fa) {
if(!dfn[e[i].to])
dis[e[i].to]=dis[x]+e[i].w,fr[e[i].to]=i,dfs(e[i].to,x);
else if(dfn[e[i].to]<dfn[x]) {
cnt++;int v=e[i].to;st[cnt]=e[i].to,ed[cnt]=x,val[cnt]=e[i].w;
ins(v,cnt,0),mark[i]=mark[i^1]=1;
int t=x;
while(t!=v) {
mark[fr[t]]=mark[fr[t]^1]=1;
ins(t,cnt,min(dis[t]-dis[v],dis[x]-dis[t]+e[i].w));
t=f[t];
}
}
}
}
int w[maxn][20],dep[maxn],d[maxn];
void dfs2(int x,int fa) {
w[x][0]=fa,dep[x]=dep[fa]+1;
for(int i=1;i<=19;i++) w[x][i]=w[w[x][i-1]][i-1];
for(int i=head[x];i;i=e[i].nxt)
if(e[i].to!=fa&&!mark[i]) d[e[i].to]=d[x]+e[i].w,dfs2(e[i].to,x);
}
int lca(int x,int y) {
if(dep[x]<dep[y]) swap(x,y);
for(int i=19;~i;i--) if(dep[w[x][i]]>=dep[y]) x=w[x][i];
if(x==y) return x;
for(int i=19;~i;i--) if(w[x][i]!=w[y][i]) x=w[x][i],y=w[y][i];
return w[x][0];
}
int approach(int x,int t) {
for(int i=19;~i;i--) if(dep[w[x][i]]>dep[t]) x=w[x][i];
return x;
}
int main() {
read(n),read(m),read(q);cnt=n;
for(int i=1,x,y,z;i<=m;i++) read(x),read(y),read(z),ins(x,y,z);
dfs(1,0),dfs2(1,0);
for(int i=1;i<=q;i++) {
int x,y;read(x),read(y);
int t=lca(x,y);
if(t<=n) {write(d[x]+d[y]-2*d[t]);continue;}
int xx=approach(x,t),yy=approach(y,t);
int ans=d[x]-d[xx]+d[y]-d[yy];
if(dis[xx]<dis[yy]) swap(xx,yy);
ans+=min(dis[xx]-dis[yy],dis[yy]-dis[st[t]]+dis[ed[t]]-dis[xx]+val[t]);
write(ans);
}
return 0;
}