HDU 2586 ( LCA/tarjan算法模板)

链接:http://acm.hdu.edu.cn/showproblem.php?pid=2586

题意:n个村庄构成一棵无根树,q次询问,求任意两个村庄之间的最短距离

思路:求出两个村庄的LCA,dis[ i ] 表示结点 i 到树根的距离,那么任意两点u,v的最短距离就是dis[ u ]  - dis [LCA] + dis [ v ] - dis[ LCA ]。代码是用tarjan做的,算是模板,记录一下。 

AC代码:

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<algorithm>
 5 #include<vector>
 6 #include<queue> 
 7 using namespace std;
 8 const int maxn = 40005;
 9 struct node{//询问的结点x,y 
10     int x,y;
11     int lca;
12 }query[maxn];
13 struct e{//建边 
14     int to;
15     int val;
16 };
17 int dis[maxn];
18 vector<e> G[maxn];
19 vector<int> Q[maxn];
20 bool vis[maxn];
21 int N;
22 int fa[maxn];
23 void init(){//初始化父亲结点 
24     for(int i = 0;i<maxn;i++) fa[i] = i;
25 }
26 int find(int x){//并查集find函数 
27     if(x == fa[x]) return x;
28     return fa[x] = find(fa[x]);
29 }
30 void tarjan(int cur){
31     vis[cur] = true;//标记cur已访问过 
32     for(auto q:Q[cur]){//遍历包含cur结点的询问 
33         if(query[q].x == cur){ 
34             if(vis[query[q].y]) {//若x == cur且y已经被访问过,搜y的祖先,就是其LCA 
35                 query[q].lca = find(query[q].y);
36             }
37         }
38         else{
39             if(vis[query[q].x]){//若y == cur且x已经被访问过,搜x的祖先,就是其LCA 
40                 query[q].lca = find(query[q].x);
41             }
42         }
43     }
44     for(auto e:G[cur]){//遍历cur结点的儿子结点 
45         int v = e.to , len = e.val ;
46         if(vis[v]) continue;
47         dis[v] = dis[cur] + len;//dis记录cur到root的距离 
48         tarjan(v);
49         fa[v] = cur; //设置cur结点子节点的父亲为cur 
50     }
51 }
52 int main(){
53     int t;scanf("%d",&t);
54     while(t--){
55         scanf("%d",&N);
56         int q;
57         memset(vis,0,sizeof(vis));
58         init();
59         for(int i = 0;i<maxn;i++) {//初始化 
60             Q[i].clear() ,G[i].clear() ;
61             query[i].lca = 0,query[i].x = 0,query[i].y = 0;
62         }
63         scanf("%d",&q);
64         for(int i = 1;i<=N-1;i++){
65             int u,v,k;
66             scanf("%d%d%d",&u,&v,&k);
67             G[u].push_back({v,k}); //建图 
68             G[v].push_back({u,k}); 
69         }
70         for(int i = 1;i<=q;i++){
71             scanf("%d%d",&query[i].x ,&query[i].y );
72             Q[query[i].x ].push_back(i);
73             Q[query[i].y ].push_back(i);  //离线存储所有询问 ,i为标号 
74         }
75         tarjan(1);
76         for(int i = 1;i<=q;i++){
77             int LCA = query[i].lca ;
78             int ans = dis[query[i].x ] + dis[query[i].y ] - 2*dis[LCA];//输出所有的询问 
79             printf("%d\n",ans);
80         }
81     }
82     return 0;
83 }
posted @ 2020-01-17 00:11  AaronChang  阅读(115)  评论(0编辑  收藏  举报