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 }

 

posted @ 2017-08-09 11:02  浅忆~  阅读(268)  评论(0编辑  收藏  举报