题解:求树上最短路,所以直接LCA:
倍增求LCA:
#include <cstdio>
int f[10010][18];
int s[10010],d[10010],from[10010];
int g[10010],nxt[20010],edv[20010],edw[20010],cnt;
bool vis[10010];
int q,a,b,e,n,m,i,j,x,y,tmp;
void swap(int &a,int &b){int c=a;a=b;b=c;}
void add(int u,int v,int w){
edv[++cnt]=v;edw[cnt]=w;
nxt[cnt]=g[u];g[u]=cnt;
}
void dfs(int x,int fa,int fr,int sum){
from[x]=fr;f[x][0]=fa;
vis[x]=1;
d[x]=d[fa]+1;
s[x]=sum;
for(int i=g[x];i;i=nxt[i])if(!vis[edv[i]])dfs(edv[i],x,fr,sum+edw[i]);
}
int lca(int x,int y){
if(x==y)return x;
if(d[x]<d[y])swap(x,y);
for(int i=17;i>=0;i--)if(d[f[x][i]]>=d[y])x=f[x][i];
if(x==y)return x;
for(int i=17;i>=0;i--)if(f[x][i]!=f[y][i])x=f[x][i],y=f[y][i];
return f[x][0];
}
int main(){
while(~scanf("%d%d%d",&n,&m,&q)){
for(i=0;i<=10000;i++)
for(j=0;j<18;j++)
f[i][j]=0;
for(i=0;i<=n;i++)vis[i]=from[i]=s[i]=d[i]=g[i]=0;
cnt=0;
for(i=0;i<m;i++){
scanf("%d%d%d",&a,&b,&e);
add(a,b,e);add(b,a,e);
}
for(i=1;i<=n;i++)if(!vis[i])dfs(i,0,i,0);
for(j=1;j<18;j++)
for(i=1;i<=n;i++)f[i][j]=f[f[i][j-1]][j-1];
for(i=0;i<q;i++){
scanf("%d%d",&x,&y);
if(from[x]!=from[y])puts("Not connected");
else printf("%d\n",s[x]+s[y]-2*s[lca(x,y)]);
}
}
return 0;
}
动态树:
#include <cstdio>
#include <cstring>
#define N 20010
using namespace std;
int f[N],son[N][2],sum[N],data[N],a[N];bool rev[N];
inline void swap(int&a,int&b){int c=a;a=b;b=c;}
inline bool isroot(int x){return !f[x]||son[f[x]][0]!=x&&son[f[x]][1]!=x;}
inline void pb(int x){
if(rev[x]){
swap(son[x][0],son[x][1]);
rev[son[x][0]]^=1;rev[son[x][1]]^=1;
rev[x]=0;
}
}
inline void up(int x){
sum[x]=data[x]+sum[son[x][0]]+sum[son[x][1]];
}
inline void rotate(int x){
int y=f[x];int w=(son[y][1]==x);
son[y][w]=son[x][w^1];
if(son[x][w^1])f[son[x][w^1]]=y;
if(f[y]){
int z=f[y];
if(son[z][0]==y)son[z][0]=x;
if(son[z][1]==y)son[z][1]=x;
}
f[x]=f[y];son[x][w^1]=y;f[y]=x;up(y);
}
inline void splay(int x){
int s=1,i=x,y;a[1]=i;
while(!isroot(i))a[++s]=i=f[i];
while(s)pb(a[s--]);
while(!isroot(x)){
y=f[x];
if(!isroot(y)){if((son[f[y]][0]==y)^(son[y][0]==x))rotate(x);else rotate(y);}
rotate(x);
}
up(x);
}
inline void access(int x){
for(int y=0;x;y=x,x=f[x]){
splay(x);
son[x][1]=y;
up(x);
}
}
inline int root(int x){
access(x);
splay(x);
while(son[x][0])x=son[x][0];
return x;
}
inline void makeroot(int x){
access(x);
splay(x);
rev[x]^=1;
}
inline void link(int x,int y){
makeroot(x);
f[x]=y;
access(x);
}
inline int getsum(int x,int y){
makeroot(x);
access(y);
splay(x);
return sum[x];
}
inline void read(int&a){
char ch;while(!((ch=getchar())>='0')&&(ch<='9'));
a=ch-'0';while(((ch=getchar())>='0')&&(ch<='9'))a*=10,a+=ch-'0';
}
int n,m,x,y,c,q;
inline void solve(){
memset(f,0,sizeof f);
memset(son,0,sizeof son);
memset(sum,0,sizeof sum);
memset(data,0,sizeof data);
memset(rev,0,sizeof rev);
read(m);read(q);
for(int i=1;i<=m;i++){
read(x);read(y);read(c);
sum[n+i]=data[n+i]=c;
link(x,n+i);link(n+i,y);
}
while(q--){
read(x);read(y);
if(root(x)!=root(y))puts("Not connected");
else printf("%d\n",getsum(x,y));
}
}
int main(){
while(~scanf("%d",&n))solve();
return 0;
}