题解:求树上最短路,所以直接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; }