众所周知
LCA(Least Common Ancestors),即最近公共祖先,是指在有根树中,找出某两个结点u和v最近的公共祖先。
LCA有四种写法。
一、倍增
fa[n][logn],fa[i][j]表示i节点的第2^j个父亲。
显然:fa[i][j]=fa[ fa[i][j-1] ][j-1]
即i的第2j个父亲是i的第2(j-1)个父亲的第2(j-1)个父亲。
于是,求i的第k个父亲的复杂度O(k)—>O(logk)
求i的第k个父亲:
1. for(int j=0; j<=log2(k); j++)
2. if((1<<j)&k) //判断二进制k的第(j-1)位是否为1
3. i=fa[i][j];
树上倍增的最基础的应用是求LCA。
区间倍增
先来道区间倍增练习一下
Eg:RMQ(洛谷ST表):数列a[N],M次询问区间[l,r]内的最大值。
思路:O(nlogn)预处理每个点起2^k的长度内的极值,O(1) 查询
常数优化:预处理g[i]=log2(i)
1. #include<bits/stdc++.h>
2. using namespace std;
3. int n,m,l,r,k,f[100005][21],g[100005];
4. inline int read() {
5. char c;
6. int ans=0;
7. while((c=getchar())=='\r'||c=='\n'||c==' ');
8. ans=ans*10+c-'0';
9. while(isdigit(c=getchar())) ans=ans*10+c-'0';
10. return ans;
11. }
12. inline void write(int x) {
13. if(x<0) putchar('-'),x=-x;
14. if(x>9) write(x/10