hdoj 2586 How far away?(最近公共祖先)
There are n houses in the village and some bidirectional roads connecting them. Every day peole always like to ask like this "How far is it if I want to go from house A to house B"? Usually it hard to answer. But luckily int this village the answer is always unique, since the roads are built in the way that there is a unique simple path("simple" means you can't visit a place twice) between every two houses. Yout task is to answer all these curious people.
InputFirst line is a single integer T(T<=10), indicating the number of test cases.
For each test case,in the first line there are two numbers n(2<=n<=40000) and m (1<=m<=200),the number of houses and the number of queries. The following n-1 lines each consisting three numbers i,j,k, separated bu a single space, meaning that there is a road connecting house i and house j,with length k(0<k<=40000).The houses are labeled from 1 to n.
Next m lines each has distinct integers i and j, you areato answer the distance between house i and house j.OutputFor each test case,output m lines. Each line represents the answer of the query. Output a bland line after each test case.Sample Input
2 3 2 1 2 10 3 1 15 1 2 2 3 2 2 1 2 100 1 2 2 1
Sample Output
10 25 100 100
1 #include <stdio.h> 2 #include <string.h> 3 #include <iostream> 4 using namespace std; 5 6 int const MAX = 40005; 7 8 struct Edge{ 9 int id, val; //当前边序号,边权 10 int next; //下一条 11 }e[2 * MAX]; 12 13 int n, m, cnt; 14 //x, y表示询问的起点和终点,z是x和y的LCA 15 int x[MAX], y[MAX], z[MAX]; 16 //fa存祖先,dist存到根的距离,pre存父亲 17 int fa[MAX], dist[MAX], pre[MAX]; 18 bool vis[MAX]; 19 20 void AddEdge(int u, int v, int w){ 21 e[cnt].id = u; 22 e[cnt].val = w; 23 e[cnt].next = pre[v]; 24 pre[v] = cnt++; 25 26 e[cnt].id = v; 27 e[cnt].val = w; 28 e[cnt].next = pre[u]; 29 pre[u] = cnt++; 30 } 31 32 int Find(int x){ 33 return x == fa[x] ? x : fa[x] = Find(fa[x]); 34 } 35 36 void tarjan(int k){ 37 vis[k] = true; 38 fa[k] = k; 39 for(int i = 1; i <= m; i++){ 40 if(x[i] == k && vis[y[i]]) 41 z[i] = Find(y[i]); 42 if(y[i] == k && vis[x[i]]) 43 z[i] = Find(x[i]); 44 } 45 for(int i = pre[k]; i != -1; i = e[i].next){ 46 if(!vis[e[i].id]){ 47 dist[e[i].id] = dist[k] + e[i].val; 48 tarjan(e[i].id); 49 fa[e[i].id] = k; 50 } 51 } 52 } 53 54 int main(){ 55 int T; 56 scanf("%d",&T); 57 while(T--){ 58 int u, v, w; 59 scanf("%d %d", &n, &m); 60 cnt = 0; 61 memset(pre, -1, sizeof(pre)); 62 for(int i = 1; i < n; i++){ 63 scanf("%d %d %d", &u, &v, &w); 64 AddEdge(u, v, w); 65 } 66 for(int i = 1; i <= n; i++) 67 x[i] = y[i] = z[i] = 0; 68 for(int i = 1; i <= m; i++){ 69 scanf("%d %d", &u, &v); 70 x[i] = u; 71 y[i] = v; 72 } 73 memset(vis, false, sizeof(vis)); 74 dist[1] = 0; 75 tarjan(1); 76 for(int i = 1; i <= m; i++) 77 printf("%d\n",dist[x[i]] + dist[y[i]] - 2 * dist[z[i]]); 78 } 79 }
1 #include <iostream> 2 #include <string.h> 3 #include <stdio.h> 4 const int N=40001; 5 struct Edge{ 6 int v,w,next; 7 }edge[2*N]; //每一条边要走两次,所以要是节点的两倍 8 9 int n,m,size,head[N]; 10 int x[N],y[N],z[N],root[N],dis[N]; 11 bool mark[N]; 12 13 //插入边 14 void Insert(int u,int v,int w){ 15 edge[size].v=v;edge[size].w=w; 16 edge[size].next=head[u];head[u]=size++; 17 edge[size].v=u;edge[size].w=w; 18 edge[size].next=head[v];head[v]=size++; 19 } 20 //查找操作 21 int Find(int x){ 22 if(root[x]!=x){ 23 return root[x]=Find(root[x]); 24 } 25 return root[x]; 26 } 27 void LCA_Tarjan(int k){ 28 mark[k]=true; 29 root[k]=k; 30 for(int i=1;i<=m;i++){ //m次询问,z[i]保存的是点x[i]和y[i]最优公共祖先 31 if(x[i]==k&&mark[y[i]])z[i]=Find(y[i]); //z[i]=y[i]; 32 if(y[i]==k&&mark[x[i]])z[i]=Find(x[i]); //z[i]=x[i] 33 } 34 for(int i=head[k];i!=-1;i=edge[i].next){ 35 if(!mark[edge[i].v]){ 36 dis[edge[i].v]=dis[k]+edge[i].w; 37 LCA_Tarjan(edge[i].v); 38 root[edge[i].v]=k; 39 } 40 } 41 } 42 int main(){ 43 int cas,u,v,w; 44 scanf("%d",&cas); 45 while(cas--){ 46 scanf("%d %d",&n, &m); 47 size=0; 48 memset(head,-1,sizeof(head)); 49 for(int i=1;i<n;i++){ 50 scanf("%d %d %d",&u, &v, &w); 51 Insert(u, v, w); 52 } 53 for(int i=1;i<=n;i++){ 54 x[i]=y[i]=z[i]=0; 55 } 56 for(int i=1;i<=m;i++){ 57 scanf("%d %d", &u, &v); 58 x[i]=u;y[i]=v; 59 } 60 memset(mark,false,sizeof(mark)); 61 dis[1]=0; 62 LCA_Tarjan(1); 63 for(int i=1;i<=m;i++) 64 printf("%d\n", dis[x[i]]+dis[y[i]]-2*dis[z[i]]); 65 } 66 return 0; 67 }