题面传送门
一道圆方树的板子题。
对于每个点先让它连到环顶。
那么他到环顶的距离就是从两边走的最小值。
那么求两点间距离就可以考虑倍增了。
但是最后要考虑特殊情况
代码实现:
#include<cstdio>
#include<cstring>
#define abs(x) ((x)>0?(x):-(x))
#define min(a,b) ((a)<(b)?(a):(b))
using namespace std;
int n,m,k,xs,y,z,fa[10039][20],lg[10039],d[10039],now,cur,tot,ans[10039],vis[10039],st[10039],sh,f1[10039],f2[10039],flag[10039],nows[10039],nh;
long long sum[10039][20];
struct yyy{int to,w,z;}tmp;
struct ljb{
int head,h[10039];
yyy f[40039];
inline void add(int x,int y,int z){
f[++head]=(yyy){y,z,h[x]};
h[x]=head;
}
}s,c;
inline void dfs(int x,int last){
int cur=s.h[x];
yyy tmp;
st[++sh]=x;vis[x]=1;
while(cur!=-1){
tmp=s.f[cur];
if(tmp.to!=last){
if(vis[tmp.to]){
if(!ans[tmp.to]){
tot++;nh=0;
while(st[sh]!=tmp.to&&sh){
c.add(tmp.to,st[sh],0);
//printf("%d %d\n",tmp.to,st[sh]);
ans[st[sh]]=tot;
if(st[sh]==x)f1[x]=tmp.w;
else f1[st[sh]]+=f1[st[sh+1]];
nows[++nh]=st[sh];
sh--;
}
nh--;
while(nh){
f2[nows[nh]]+=f2[nows[nh+1]];
nh--;
}
}
}
else{
if(!ans[x]) f1[x]=tmp.w;
f2[tmp.to]=tmp.w;
dfs(tmp.to,x);
}
}
cur=tmp.z;
}
if(!ans[x]) sh--,f1[x]=f2[x],c.add(last,x,0)/*,printf("%d %d\n",last,x)*/;
}
inline void dfss(int x,int last){
fa[x][0]=last;sum[x][0]=min(f1[x],f2[x]);
d[x]=d[last]+1;
for(int k=1;k<=lg[d[x]];k++)sum[x][k]=sum[fa[x][k-1]][k-1]+sum[x][k-1],fa[x][k]=fa[fa[x][k-1]][k-1];
int cur=c.h[x];
yyy tmp;
while(cur!=-1){
tmp=c.f[cur];
if(tmp.to!=last) dfss(tmp.to,x);
cur=tmp.z;
}
}
inline void swap(int &x,int &y){x^=y,y^=x,x^=y;}
inline long long lca(int x,int y){
long long anss=0;
if(d[x]<d[y]) swap(x,y);
while(d[x]>d[y]) anss+=sum[x][lg[d[x]-d[y]]-1],x=fa[x][lg[d[x]-d[y]]-1];
if(x==y)return anss;
for(int k=lg[d[x]];k>=0;k--) if(fa[x][k]!=fa[y][k]) anss+=sum[x][k]+sum[y][k],x=fa[x][k],y=fa[y][k];
//printf("%d %d %d\n",x,y,anss);
if(ans[x]==ans[y]&&ans[x]) return anss+min(abs(f1[x]-f1[y]),min(f1[x]+f2[y],f2[x]+f1[y]));
else return anss+sum[x][0]+sum[y][0];
}
int main(){
// freopen("1.in","r",stdin);
// freopen("1.out","w",stdout);
memset(s.h,-1,sizeof(s.h));
memset(c.h,-1,sizeof(c.h));
register int i;
scanf("%d%d%d",&n,&m,&k);
for(i=1;i<=n;i++)lg[i]=lg[i-1]+(1<<lg[i-1]==i);
for(i=1;i<=m;i++) scanf("%d%d%d",&xs,&y,&z),s.add(xs,y,z),s.add(y,xs,z);
dfs(1,0);
//for(i=1;i<=n;i++) printf("%d %d\n",f1[i],f2[i]);
dfss(1,0);
for(i=1;i<=k;i++) scanf("%d%d",&xs,&y),printf("%lld\n",lca(xs,y));
}