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 }