题目链接: poj 1986
题目大意: 给出一棵树,求a—b路径的长度
解题思路: 与hdu 2874类似
LCA离线查找最近公共祖先
dist[ ]求距离: 距离=dist[ a ] + dist[ b ] — 2*dist[ LCA(a,b) ]
代码:
//Final LCA离线 查找两点最短距离 #include <stdio.h> #include <string.h> #include <stdlib.h> #define MAX 50100 struct { int to,w,next; }Hash[MAX<<2],Qes[MAX<<2]; //Hash是存在的边,Qes是需要查询点 int n,Index1,Index2,pre1[MAX],pre2[MAX],visit[MAX],ansetor[MAX],ans[MAX],dist[MAX]; void Add_edge(int a,int b,int c) //建立树 { Hash[Index1].to=b,Hash[Index1].w=c; Hash[Index1].next=pre1[a]; pre1[a]=Index1++; } void Add_Qes(int a,int b,int c) //建立离线查询 { Qes[Index2].to=b,Qes[Index2].w=c; Qes[Index2].next=pre2[a]; pre2[a]=Index2++; } int Find(int x) //最近公共祖先查找 { int s,j; s=x; while(x!=ansetor[x]) x=ansetor[x]; while(s!=x) { j=ansetor[s]; ansetor[s]=x; s=j; } return x; } void LCA(int u) //离线查找最近公共祖先,并且在线更新当前点到根结点的距离 { int i,v; visit[u]=1; ansetor[u]=u; for(i=pre1[u];i!=-1;i=Hash[i].next) { v=Hash[i].to; if(!visit[v]) //如果此点没有访问过,则更新dist[] { dist[v]=dist[u]+Hash[i].w; LCA(v); //回溯 ansetor[v]=u; //当前点的祖先暂时是u } } for(i=pre2[u];i!=-1;i=Qes[i].next) { v=Qes[i].to; if(visit[v]) //如果这个点之前访问过,那么它最近的祖先也就确定了 { ans[Qes[i].w]=dist[u]+dist[v]-dist[ansetor[Find(v)]]*2; } } } int main() { char ch[2]; int m,k,i,a,b,c; while(scanf("%d%d",&n,&m)!=EOF) { Index1=Index2=0; memset(ans,-1,sizeof(ans)); memset(pre1,-1,sizeof(pre1)); memset(pre2,-1,sizeof(pre2)); memset(dist,0,sizeof(dist)); memset(visit,0,sizeof(visit)); memset(ansetor,0,sizeof(ansetor)); for(i=0;i<m;i++) { scanf("%d%d%d%s",&a,&b,&c,ch); Add_edge(a,b,c); //**如果树有结构的才用fathernum[] Add_edge(b,a,c); //** } scanf("%d",&k); for(i=1;i<=k;i++) { scanf("%d%d",&a,&b); Add_Qes(a,b,i); Add_Qes(b,a,i); } for(i=1;i<=n;i++) { if(!visit[i]) //**没有访问过的点开始访问,如果树有结构的才从fathernum[]出发! LCA(i); } for(i=1;i<=k;i++) { printf("%d\n",ans[i]); } } return 0; }