码迷,mamicode.com
首页 > 其他好文 > 详细

HDU 2586 LCA

时间:2015-08-08 12:00:54      阅读:184      评论:0      收藏:0      [点我收藏+]

标签:

 题目大意:

多点形成一棵树,树上边有权值,给出一堆询问,求出每个询问中两个点的距离

 

这里求两个点的距离可以直接理解为求出两个点到根节点的权值之和,再减去2倍的最近公共祖先到根节点的距离

这是自己第一道lca题目

学习了两种方法

 

第一种在ST算法,利用RMQ思想预处理

技术分享
 1 /*在线ST算法*/
 2 #pragma comment(linker, "/STACK:102400000,102400000")
 3 #include <cstdio>
 4 #include <iostream>
 5 #include <cstring>
 6 #include <algorithm>
 7 using namespace std;
 8 #define N 40010
 9 
10 int first[N] , k;
11 
12 struct Edge{
13     int x , y , w , next;
14     Edge(){}
15     Edge(int x , int y , int w , int next):x(x),y(y),w(w),next(next){}
16 }e[N<<1];
17 
18 void add_edge(int x , int y , int w)
19 {
20     e[k] = Edge(x , y , w , first[x]);
21     first[x] = k++;
22 }
23 int dp[N<<1][28];
24 int id[N<<1] , dep[N<<1] , dis[N] , No[N] , dfs_clock;
25 void dfs(int u , int f , int d)
26 {
27     id[++dfs_clock] = u , No[u] = dfs_clock , dep[dfs_clock] = d;
28     for(int i=first[u] ; ~i ; i=e[i].next){
29         int v = e[i].y;
30         if(v == f) continue;
31         dis[v] = dis[u]+e[i].w;
32         dfs(v , u , d+1);
33         id[++dfs_clock] = u , dep[dfs_clock] = d;
34     }
35 }
36 
37 void ST(int n)
38 {
39     for(int i=1 ; i<=n ; i++) dp[i][0] = i;
40     for(int j=1 ; (1<<j)<=n ; j++){
41         for(int i=1 ; i+(1<<j)-1<=n ; i++){
42             int a = dp[i][j-1] , b = dp[i+(1<<(j-1))][j-1];
43             dp[i][j] = dep[a]<dep[b]?a:b;
44         }
45     }
46 }
47 
48 int RMQ(int l , int r)
49 {
50     int k=0;
51     while((1<<(k+1))<=r-l+1) k++;
52     int a = dp[l][k] , b = dp[r-(1<<k)+1][k];
53     return dep[a]<dep[b]?a:b;
54 }
55 
56 int LCA(int u , int v)
57 {
58     int x = No[u] , y = No[v];
59     if(x>y) swap(x , y);
60     return id[RMQ(x , y)];
61 }
62 
63 int n , m;
64 
65 int main()
66 {
67    // freopen("in.txt" , "r" , stdin);
68     int T , x , y , w;
69     scanf("%d" , &T);
70     while(T--)
71     {
72         scanf("%d%d" , &n , &m);
73         memset(first , -1 , sizeof(first));
74         k = 0;
75         for(int i=1 ; i<n ; i++){
76             scanf("%d%d%d" , &x , &y , &w);
77             add_edge(x , y , w);
78             add_edge(y , x , w);
79         }
80         dfs_clock = 0;
81         dis[1] = 0;
82         dfs(1 , 0 , 1);
83         ST(2*n-1);
84         while(m--){
85             scanf("%d%d" , &x , &y);
86             int anc = LCA(x , y);
87             printf("%d\n" , dis[x]-2*dis[anc]+dis[y]);
88         }
89     }
90     return 0;
91 }
ST算法

第二种是离线的Tarjan算法,利用并查集的思想解决

技术分享
 1 /*在线ST算法*/
 2 #pragma comment(linker, "/STACK:102400000,102400000")
 3 #include <cstdio>
 4 #include <iostream>
 5 #include <cstring>
 6 #include <algorithm>
 7 using namespace std;
 8 #define N 40010
 9 #define M 205
10 int first[N] , k;
11 
12 struct Edge{
13     int x , y , w , next;
14     Edge(){}
15     Edge(int x , int y , int w , int next):x(x),y(y),w(w),next(next){}
16 }e[N<<1];
17 
18 int _first[N] , _k;
19 
20 struct Que{
21     int v , lca , next;
22     Que(){}
23     Que(int v , int lca , int next):v(v),lca(lca),next(next){}
24 }eq[M<<1];
25 
26 void add_edge(int x , int y , int w)
27 {
28     e[k] = Edge(x , y , w , first[x]);
29     first[x] = k++;
30 }
31 
32 void add_que_edge(int x , int y)
33 {
34     eq[_k] = Que(y , 0 , _first[x]);
35     _first[x] = _k++;
36 }
37 
38 int fa[N] , dis[N];
39 bool vis[N];
40 int find(int x){return x==fa[x]?x:fa[x]=find(fa[x]);}
41 
42 void tarjan(int u)
43 {
44     vis[u] = true , fa[u] = u;
45     for(int i=first[u] ; ~i ; i=e[i].next){
46         int v = e[i].y;
47         if(vis[v]) continue;
48         dis[v] = dis[u]+e[i].w;
49         tarjan(v);
50         fa[v] = u;
51     }
52     for(int i=_first[u] ; ~i ; i=eq[i].next){
53         int v = eq[i].v;
54         if(vis[v]) eq[i].lca = eq[i^1].lca = find(eq[i].v);
55     }
56 }
57 int n , m;
58 
59 int main()
60 {
61    // freopen("in.txt" , "r" , stdin);
62     int T , x , y , w;
63     scanf("%d" , &T);
64     while(T--)
65     {
66         scanf("%d%d" , &n , &m);
67         memset(first , -1 , sizeof(first));
68         k = 0;
69         for(int i=1 ; i<n ; i++){
70             scanf("%d%d%d" , &x , &y , &w);
71             add_edge(x , y , w);
72             add_edge(y , x , w);
73         }
74         memset(_first , -1 , sizeof(_first));
75         _k = 0;
76         for(int i=0 ; i<m ; i++){
77             scanf("%d%d" , &x , &y);
78             add_que_edge(x , y);
79             add_que_edge(y , x);
80         }
81         memset(vis , 0 , sizeof(vis));
82         tarjan(1);
83         for(int i=0 ; i<m*2 ; i+=2){
84             int lca = eq[i].lca;
85             printf("%d\n" , dis[eq[i].v]-2*dis[lca]+dis[eq[i^1].v]);
86         }
87     }
88     return 0;
89 }
Tarjan算法

 

HDU 2586 LCA

标签:

原文地址:http://www.cnblogs.com/CSU3901130321/p/4712771.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!