倍增算法2(树上倍增)
Posted lnu161403214
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了倍增算法2(树上倍增)相关的知识,希望对你有一定的参考价值。
还是基本的问题,求LCA。
详情见:
https://blog.csdn.net/saramanda/article/details/54963914
讲得非常好了。
fa[i][j]=fa[ fa[i][j-1] ][j-1]
用文字叙述为:i的第2^j个父亲 是i的第2^(j-1)个父亲的第2^(j-1)个父亲。
很有回溯的味道,实现也是用的回溯法(dfs),注意这里的第二维表示是i+2^j,而上一篇文章的是i+2^j-1。
任何一个数换成二进制后,都能想到可由∑2x 表示,一个长区间便能用logn个小区间凑起来,知道了这个性质便能很好的理解代码。
1 #include<algorithm>
2 #include<iostream>
3 #include<cstring>
4 #include<cstdio>
5 #include<cmath>
6 #include<vector>
7 using namespace std;
8 const int maxn = 100005;
9 const int max0 = 25;
10 int fa[maxn][max0+5]={0},dep[maxn];
11 vector<int>vt[maxn];
12 void dfs(int x)
13 { //更新x的st表
14 for(int i=1;i<=max0;i++)
15 if(fa[x][i-1])
16 {
17 fa[x][i]=fa[fa[x][i-1]][i-1];
18
19 }
20 else break;
21
22 int l=vt[x].size();
23 for(int i=0;i<l;i++)
24 { int t=vt[x][i];
25
26 if(t!=fa[x][0]) //无向图也行
27 {
28 fa[t][0]=x;
29 dep[t]=dep[x]+1;
30 dfs(t);
31 }
32 }
33 }
34
35 int LCA(int u,int v)
36 { //对齐
37 if(dep[u]<dep[v])swap(u,v);
38 int delta=dep[u]-dep[v];
39
40 for(int x=0;x<=max0;x++) //倍增凑步数
41 if((1<<x)&delta)
42 u=fa[u][x];
43 if(u==v)return u;
44
45 //同时向LCA跳跃
46 for(int x=max0;x>=0;x--) //由大到小凑数
47 if(fa[u][x]!=fa[v][x]) //判断是否超过LCA
48 {
49 u=fa[u][x];
50 v=fa[v][x];
51 }
52
53 return fa[u][0];
54 }
55 int ind[maxn];
56 int main()
57 {
58 int n;
59 cin>>n;
60
61 for(int i=1;i<n;i++)
62 {
63 int x,y;
64 cin>>x>>y;
65 vt[x].push_back(y); //有向图
66 ind[y]++; //入度++
67 }
68 int i=1;
69
70 for(;i<=n;i++)
71 {
72 if(ind[i]==0) break;
73 }
74 dfs(i);
75 int m;
76 cin>>m;
77 while(m--)
78 {
79 int x,y;
80 cin>>x>>y;
81 cout<<LCA(x,y)<<endl;
82
83 }
84 }
85
以上是关于倍增算法2(树上倍增)的主要内容,如果未能解决你的问题,请参考以下文章