标签:
http://acm.hdu.edu.cn/showproblem.php?pid=2586
2 3 2 1 2 10 3 1 15 1 2 2 3 2 2 1 2 100 1 2 2 1
10 25 100 100
/** hdu 2586 LCA模板题(离线算法) 题目大意:给一个无根树,有q个询问,每个询问两个点,问两点的距离。 解题思路:求出 lca = LCA(X,Y) , 然后 dir[x] + dir[y] - 2 * dir[lca], dir[u]表示点u到树根的距离 */ #include <stdio.h> #include <string.h> #include <iostream> #include <algorithm> using namespace std; const int maxn=40010; struct note { int u,v,w,lca,next; }edge[maxn*2],edge1[805]; int head[maxn],ip,head1[maxn],ip1; int m,n; int father[maxn],vis[maxn],ance[maxn],dir[maxn]; void init() { memset(vis,0,sizeof(vis)); memset(dir,0,sizeof(dir)); memset(head,-1,sizeof(head)); memset(head1,-1,sizeof(head1)); ip=ip1=0; } void addedge(int u,int v,int w) { edge[ip].v=v,edge[ip].w=w,edge[ip].next=head[u],head[u]=ip++; } void addedge1(int u,int v) { edge1[ip1].u=u,edge1[ip1].v=v,edge1[ip1].lca=-1,edge1[ip1].next=head1[u],head1[u]=ip1++; } int Find(int x) { if(father[x]==x) return x; return father[x]=Find(father[x]); } void Union(int x,int y) { x=Find(x); y=Find(y); if(x!=y) father[y]=x; } void tarjan(int u) { vis[u]=1; ance[u]=father[u]=u; for(int i=head[u];i!=-1;i=edge[i].next) { int v=edge[i].v; int w=edge[i].w; if(!vis[v]) { dir[v]=dir[u]+w; tarjan(v); Union(u,v); } } for(int i=head1[u];i!=-1;i=edge1[i].next) { int v=edge1[i].v; if(vis[v]) { edge1[i].lca=edge1[i^1].lca=ance[Find(v)]; } } } int main() { int T; scanf("%d",&T); while(T--) { init(); scanf("%d%d",&n,&m); for(int i=1;i<n;i++) { int u,v,w; scanf("%d%d%d",&u,&v,&w); addedge(u,v,w); addedge(v,u,w); } for(int i=0;i<m;i++) { int u,v; scanf("%d%d",&u,&v); addedge1(u,v); addedge1(v,u); } dir[1]=0; tarjan(1); for(int i=0;i<m;i++) { int s=i*2,u=edge1[s].u,v=edge1[s].v,lca=edge1[s].lca; printf("%d\n",dir[u]+dir[v]-2*dir[lca]); } } return 0; }
标签:
原文地址:http://blog.csdn.net/lvshubao1314/article/details/44001481