LCA

倍增算法:

每个数都可以用二进制表示,2^30是一个很大的数,所以可以从二进制的第三十位开始,往后找,可以根据条件找到最大最合适的数。

例题:

C - Closest Common Ancestors

Write a program that takes as input a rooted tree and a list of pairs of vertices. For each pair (u,v) the program determines the closest common ancestor of u and v in the tree. The closest common ancestor of two nodes u and v is the node w that is an ancestor of both u and v and has the greatest depth in the tree. A node can be its own ancestor (for example in Figure 1 the ancestors of node 2 are 2 and 5)
The data set starts with the tree description, in the form:
nr_of_vertices
vertex:(nr_of_successors) successor1 successor2 ... successorn
......
where vertices are represented as integers from 1 to n. The tree description is followed by a list of pairs of vertices, in the form:
nr_of_pairs
(u v) (x y) ...
The input contents several data sets (at least one).
Note that white-spaces (tabs, spaces and line breaks) can be used freely in the input.
For each common ancestor the program prints the ancestor and the number of pair for which it is an ancestor. The results are printed on the standard output on separate lines, in to the ascending order of the vertices, in the format: ancestor:times
For example, for the following tree:

                                                   

the program input and output is:
Input

5
5:(3) 1 4 2
1:(0)
4:(0)
2:(1) 3
3:(0)
6
(1,5) (1,4) (4,2)
(2,3)
(1,3) (4,3)
Output

2:1
5:5

题意:给你一个有根数让你输出他所给的任意两点的最近祖先。输入有毒!!!

解题思路:

套用LCA倍增法模板即可,将所给点的祖先存到一个数组中,然后由小到大逐一输出。

代码:

 1 #include <iostream>
 2 #include <stdio.h>
 3 #include <map>
 4 #include <vector>
 5 #include <string.h>
 6 #include <math.h>
 7 #include <algorithm>
 8 using namespace std;
 9 typedef long long ll;
10 const ll N=1e4+100;
11 ll bit[30];//存放2^i的数值大小 
12 vector<int> mp[N];//建图 
13 ll depth[N];//每个节点距离根节点的深度。 
14 ll pre[N][30];//存放每个节点的祖先。 
15 ll print[N];//最后的输出 
16 void init(int n){//初始化 
17     bit[0]=1;
18     for(int i=1;i<=29;i++){
19         bit[i]=bit[i-1]*2;//求二进制数的十进制大小。 
20     }
21     for(int i=0;i<=n;i++){
22         mp[i].clear();//清空数组 
23     }
24     memset(depth,0,sizeof(depth));
25     memset(pre,0,sizeof(pre));
26     memset(print,0,sizeof(print));
27 }
28 void dfs(int s,int p){//套用模板 
29     pre[s][0]=p;//他的父亲 
30     depth[s]=depth[p]+1;//深度是他父亲+1; 
31     for(int i=1;i<=29;i++){
32         pre[s][i]=pre[pre[s][i-1]][i-1];//2^i=2^(i-1)+2^(i-1) 
33     }
34     for(int i=0;i<mp[s].size();i++){
35         if(mp[s][i]==p) continue;//向下查找 
36         dfs(mp[s][i],s);//初始化下一个点 
37     }
38 }
39 
40 int LCA(int a,int b){
41     if(depth[a]<depth[b]){
42         swap(a,b);
43     }
44     int dif=depth[a]-depth[b];//相距深度 
45     for(int i=29;i>=0;i--){//先将下边的提到上边使深度相同 
46         if(dif>=bit[i]){
47             a=pre[a][i];
48             dif-=bit[i];
49         }
50     }
51     if(a==b)return a;
52     for(int i=29;i>=0;i--){
53         if(depth[a]>=bit[i]&&pre[a][i]!=pre[b][i]){//找最上边的一个他们的父亲结点相同但两个节点不同 
54             a=pre[a][i];
55             b=pre[b][i];
56         }
57     }
58     return pre[a][0];//输出那两个节点的共同父亲结点 
59 }
60 int main(){
61     int n,a,b,c;
62     while(cin>>n){
63         map<int,int>mp1;//查询根节点 
64         init(n);
65         for(int i=1;i<=n;i++){
66             scanf("%d:(%d)", &a, &b);
67             for(int j=1;j<=b;j++){
68                 scanf("%d",&c);
69                 mp1[c]++;//c就不是根节点,标记。 
70                 mp[a].push_back(c);//存图 
71                 mp[c].push_back(a);
72             }
73         }
74         for(int i=1;i<=n;i++){
75             if(mp1[i]==0){
76                 dfs(i,0);//找根节点 
77                 break;
78             }
79         }
80         scanf("%d",&a);
81         for(int i=1;i<=a;i++){
82             scanf(" (%d,%d)",&b,&c);//输入时左侧可能有空格。 
83             print[LCA(b,c)]++;
84         }
85         for(int i=1;i<=n;i++){
86             if(print[i]){
87                 printf("%d:%d\n",i,print[i]);//输出 
88             }
89         }
90     }
91 
92     return 0;
93 }
View Code

 

D - 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.

Input

First 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.

Output

For 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

题目大意:

给一个带权有根图,给你任意两个点,你要找出他们两个点相距的距离。

解题思路:

任意找个点为根节点,然后向下寻找,记录每个结点与根结点相距的距离。可以知道,一个点的到根结点的距离是他到他父亲的距离加上他父亲到根结点的距离。最后通过LCA找到最近祖先通过三结点距离根结点的距离算出两点之间的距离。

代码:

 1 #include <iostream>
 2 #include <stdio.h>
 3 #include <map>
 4 #include <vector>
 5 #include <string.h>
 6 #include <math.h>
 7 #include <algorithm>
 8 using namespace std;
 9 typedef long long ll;
10 const ll N=4e4+100;
11 struct aa{
12     int v,d;
13 };
14 ll lenth[N];
15 ll bit[30];
16 vector<aa> mp[N];
17 ll depth[N];
18 int pre[N][30];
19 
20 void init(int n){
21     bit[0]=1;
22     for(int i=1;i<=29;i++){
23         bit[i]=bit[i-1]*2;
24     }
25     for(int i=0;i<=n;i++){
26         mp[i].clear();
27     }
28     memset(depth,0,sizeof(depth));
29     memset(pre,0,sizeof(pre));
30     memset(lenth,0,sizeof(lenth));
31 }
32 
33 void dfs(int s,int p){
34     pre[s][0]=p;
35     depth[s]=depth[p]+1;
36     for(int i=1;i<=29;i++){
37         pre[s][i]=pre[pre[s][i-1]][i-1];
38     }
39     for(int i=0;i<mp[s].size();i++){
40         if(mp[s][i].v==p) continue;
41         lenth[mp[s][i].v]+=(lenth[s]+mp[s][i].d);//这个节点距离根节点的距离。 
42         dfs(mp[s][i].v,s);
43     }
44 }
45 
46 int LCA(int a,int b){
47     int l1=lenth[a],l2=lenth[b];//任意两点到根节点的距离 
48     if(depth[a]<depth[b]){
49         swap(a,b);
50     }
51     int dif=depth[a]-depth[b];
52     for(int i=29;i>=0;i--){
53         if(dif>=bit[i]){
54             a=pre[a][i];
55             dif-=bit[i];
56         }
57     }
58     if(a==b){
59         return l1+l2-2*lenth[a];//计算 
60         
61     }
62     for(int i=29;i>=0;i--){
63         if(depth[a]>=bit[i]&&pre[a][i]!=pre[b][i]){
64             a=pre[a][i];
65             b=pre[b][i];
66         }
67     }
68     return l1+l2-2*lenth[pre[a][0]];//计算 
69     
70 }
71 
72 int main(){
73     int t,n,m,a,b,c;
74     cin>>t;
75     while(t--){
76         cin>>n>>m;
77         map<int,int>mp1;
78         init(n);
79         for(int i=1;i<=n-1;i++){
80             scanf("%d%d%d",&a,&b,&c);
81             mp[a].push_back({b,c});
82             mp[b].push_back({a,c});
83         }
84         dfs(1,0);
85         for(int i=1;i<=m;i++){
86             scanf("%d %d)",&b,&c);
87             cout<<LCA(b,c)<<endl;
88         }
89     }
90     
91     
92     
93     return 0;
94 }
View Code

 

       

 

posted @ 2019-08-08 20:47  yya雨  阅读(252)  评论(0编辑  收藏  举报