Description
Data Constraint
Solution
我被坑了,他的环是指一个边双联通分量……
我们若处理出起点到每个点的最短距离d,那么若询问x,y的lca不在一个环上,那么答案显然是d[x]+d[y]-2*d[lca],那么若lca在环上呢?我们处理出起点到每个点的在dfs树上的距离deep[x]和每个边双的长度len,那么显然环上两个点x,y的最小距离即min(|deep[x]-deep[y]|,len-|deep[x]-deep[y]|)。若询问u,v刚走进lca所在环的点分别为x,y,那么答案即d[u]+d[v]-d[x]-d[y]+min(|deep[x]-deep[y]|,len-|deep[x]-deep[y]|).现在问题的关键转化为如何求x,y。我们将一个边双除顶点以外的点都连向顶点,那么在求u,v的lca时倍增到只差一步重合的时候那两个点即所求的x,y。
Code
#include<iostream>
#include<cmath>
#include<cstring>
#include<cstdio>
#include<algorithm>
using namespace std;
const int maxn=4e5+5;
int first[maxn],last[maxn],next[maxn],d[maxn],deep[maxn],value[maxn],bz[maxn];
int n,m,q,i,t,j,k,l,x,y,z,num,ln,xx,yy,num1,low[maxn],ans;
int f[maxn][20],fa[maxn],len[maxn],dis[maxn],bz1[maxn],p[maxn],id[maxn],dfn[maxn];
void lian(int x,int y,int z){
last[++num]=y;next[num]=first[x];first[x]=num;value[num]=z;id[num]=i;
}
void dg(int x,int y){
int t;bz[x]=1;p[++p[0]]=x;dfn[x]=low[x]=++num1;
for (t=first[x];t;t=next[t]){
if (id[t]==y) continue;
if (bz[last[t]]==2){
if (fa[last[t]]==x) len[bz1[last[t]]]+=value[t];
continue;
}else if (!bz[last[t]]){
d[last[t]]=d[x]+value[t];
dg(last[t],id[t]);
if (low[last[t]]>=dfn[x]){
if (p[p[0]]!=last[t]){
++num;len[num]=d[p[p[0]]]-d[x];
while (p[p[0]]!=x) f[p[p[0]]][0]=x,bz1[p[p[0]]]=num,fa[p[p[0]]]=x,bz[p[p[0]--]]=2;
}else p[0]--;
}
}
low[x]=min(low[x],low[last[t]]);
}
}
void dg1(int x){
int t;bz[x]=1;
for (t=first[x];t;t=next[t]){
if (bz[last[t]]) continue;
if (fa[last[t]]) k=d[last[t]]-d[fa[last[t]]],dis[last[t]]=dis[fa[last[t]]]+min(len[bz1[last[t]]]-k,k),deep[last[t]]=deep[fa[last[t]]]+1;
else bz1[last[t]]=++num,f[last[t]][0]=x,dis[last[t]]=dis[x]+value[t],deep[last[t]]=deep[x]+1;
dg1(last[t]);
}
}
int main(){
// freopen("data.in","r",stdin);freopen("data.out","w",stdout);
scanf("%d%d%d",&n,&m,&q);
for (i=1;i<=m;i++)
scanf("%d%d%d",&x,&y,&z),lian(x,y,z),lian(y,x,z);
num=0;dg(1,0);memset(bz,0,sizeof(bz));
dg1(1);
ln=log(num)/log(2);
for (j=1;j<=ln;j++)
for (i=1;i<=n;i++)
f[i][j]=f[f[i][j-1]][j-1];
deep[0]=-1;
for (i=1;i<=q;i++){
scanf("%d%d",&x,&y);xx=x;yy=y;
if (deep[x]<deep[y]) swap(x,y);
for (j=ln;j>=0;j--)
if (deep[f[x][j]]>=deep[y]) x=f[x][j];
if (x==y) ans=dis[xx]+dis[yy]-2*dis[y],printf("%d\n",ans);
else{
if (bz1[x]==bz1[y]) ans=dis[xx]+dis[yy]-dis[x]-dis[y]+min(abs(d[x]-d[y]),len[bz1[x]]-abs(d[x]-d[y])),printf("%d\n",ans);
else{
for (j=ln;j>=0;j--)
if (bz1[f[x][j]]!=bz1[f[y][j]]) x=f[x][j],y=f[y][j];
x=f[x][0];y=f[y][0];
ans=dis[xx]+dis[yy]-dis[x]-dis[y]+min(abs(d[x]-d[y]),len[bz1[x]]-abs(d[x]-d[y]));
printf("%d\n",ans);
}
}
}
}