LCA算法倍增算法(洛谷3379模板题)

倍增(爬树)算法,刚刚学习的算法。对每一个点的父节点,就记录他的2k的父亲。

题目为http://www.luogu.org/problem/show?pid=3379

第一步先记录每一个节点的深度用一个深搜,顺便对每个节点的20赋初值为自己的上一个节点。

第二步通过第一步的初始化对每个节点的2k次进行赋值为fa[i][j]=fa[ fa[i][j-1] ][ j-1 ];自己的j-1次幂的父节点的i-1次就是就是自己的j次幂。

第三步对询问做出处理

    1,先判断x,y的深度,如果x比y浅就换位置,让x为深的节点

    2,让x上升到和y一样的高度

    3,找到他们两个第一个相等的点,一直上升2k次,直到不相等了就让x和y等于他,输出的时候输出的值是fa[x][0]也就是他的上一个点,这是他们相等的点。

输入:N、M、S,分别表示树的结点个数、询问的个数和树根结点的序号。

接下来N-1行每行包含两个正整数x、y,表示x结点和y结点只见有一条直接连接的边(数据保证可以构成树)。

接下来M行每行包含两个正整数a、b,表示询问a结点和b结点的最近公共祖先。

输出包含M行,每行包含一个正整数,依次为每一个询问的结果。

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cmath>
 4 #include<cstring>
 5 using namespace std;
 6 #define MAX 500010
 7 //=================================================
 8 struct NODE{
 9         int next,point;
10         NODE(){ next=0; }
11     }edge[1000010];
12 //=================================================
13 int N,M,S;
14 int link[MAX],edgenum=0,fa[MAX][11];
15 int deep[MAX];
16 //=================================================
17 void init();
18 void ADD(int ,int );
19 void DFS(int );
20 void find();
21 void pt();
22 int LCA(int x,int y);
23 //=================================================
24 int LCA(int x,int y)
25 {
26     if(deep[x]<deep[y])swap(x,y);  //如果x比y浅,就让他们两个交换,让x为比较深的那个
27     for(int i=10;i>=0;i--){       //注意这里是倒叙,从大k到小k,如果x的k次幂比y深或等于y的深度了就让x等于过去,然后k还会减小
28         if( deep[ fa[x][i] ] >= deep[y] )  //这样x就可以慢慢逼近直到等于y的深度
29             x=fa[x][i];           //将x上升到跟y一样的高度上
30     }
31     if(x==y)return x;
32     for(int i=10;i>=0;i--){    //这里和上边一样,倒叙进行
33         if( fa[x][i]!=fa[y][i] )  //一只循环到x的0次和y的0次相等的时候,但是这个时候x不等于y也不是公共祖先
34             x=fa[x][i],y=fa[y][i];  //他们的公共祖先是x的0次幂或y的0次幂所以返回的值是fa[x][0];
35     }
36     return fa[x][0];
37 }
38 //=================================================
39 void pt()
40 {
41     for(int i=1;i<=M;i++){
42         int x,y;
43         scanf("%d%d*c",&x,&y);
44         printf("%d\n",LCA(x,y));
45     }
46 }
47 //=================================================
48 void find()
49 {
50     for(int i=1;i<=10;i++){
51         for(int j=1;j<=N;j++){
52             fa[j][i]=fa[ fa[j][i-1] ][i-1];     //确定自己的所有倍增父节点
53         }
54     }
55 }
56 //=================================================
57 void DFS(int u)
58 {
59     for(int i=link[u];i!=0;i=edge[i].next){
60         int v=edge[i].point;
61         if(deep[v]==0){
62             deep[v]=deep[u]+1;  //下一个点的深度为这个点的深度加一
63             fa[v][0]=u;         //2的0次幂就是自己的父节点
64             DFS(v);
65         }
66     }
67 }
68 //=================================================
69 void ADD(int x,int y)
70 {
71     edgenum++;
72     edge[edgenum].point=y;
73     edge[edgenum].next=link[x];
74     link[x]=edgenum;
75 }
76 //=================================================
77 void init()
78 {
79     scanf("%d%d%d",&N,&M,&S);
80     for(int i=1;i<N;i++){
81         int x,y;
82         scanf("%d%d*c",&x,&y);
83         ADD(x,y);
84         ADD(y,x);
85     }
86 }
87 //=================================================
88 int main()
89 {
90     init();  //初始化
91     deep[S]=1;
92     DFS(S);  //深搜找深度
93     find();  //找每个点的2k次父节点
94     pt();   //输入询问输出答案
95     return 0;
96 }

 

posted on 2016-10-05 11:33  fuyun_boy  阅读(297)  评论(0编辑  收藏  举报

导航