倍增版LCA
lac即最近公共祖先,u和v最近公共祖先就是两节点公用的祖先中深度最大的
比如
其中
lca(1,2)=4,
lca(2,3)=4,
lca(3,5)=1,
lca(2,5)=4;
如何求LCA?
树上倍增版:
- 预处理每一个节点的深度
depth[i]
; - 选定两节点;
- 将深度大的节点往上跳,跳到与另一节点相同深度;
- 然后两个节点一起往上跳,直到两个节点重合;
- 那么这个节点就是两个节点的lca;
那么怎么让计算机实现“跳”?
我们可以用倍增思想
设f[i][j]
表示第i个节点往上跳2^j个节点所到达的祖先
那么f[i][j]=f[f[i][j-1]][j-1]
意思是
从i往上跳2j个节点所到达的节点可以转化为从i往上跳2(j-1)再往上跳2^(j-1)个,而f[i][j-1]在之前通过递推已经推出来了
初始化Code:
void init() { for(int j=1;j<=N;j++) { for(int i=1;i<=n;i++) f[i][j]=f[f[i][j-1]][j-1]; } }
题目
给定一棵有根多叉树,请求出指定两个点直接最近的公共祖先。
输入格式:
第一行包含三个正整数N、M、S,分别表示树的结点个数、询问的个数和树根结点的序号。
接下来N-1行每行包含两个正整数x、y,表示x结点和y结点之间有一条直接连接的边(数据保证可以构成树)。
接下来M行每行包含两个正整数a、b,表示询问a结点和b结点的最近公共祖先。
输出格式:
输出包含M行,每行包含一个正整数,依次为每一个询问的结果。
输入样例#1:
5 5 4 3 1 2 4 5 1 1 4 2 4 3 2 3 5 1 2 4 5
输出样例#1:
4 4 1 4 4
说明
时空限制:1000ms,128M
数据规模:
对于30%的数据:N<=10,M<=10
对于70%的数据:N<=10000,M<=10000
对于100%的数据:N<=500000,M<=500000
#include <cstdio> #include <iostream> #include <cmath> using namespace std; int head[500010],depth[500010]; int n,m,s,cnt,f[500010][20]; int N=0; bool vis[500010]; struct Edge { int next; int to; }e[500010]; inline int Read(){ int x=0,f=1;char c=getchar(); while(c>'9'||c<'0') {if(c=='-') f=-1;c=getchar();} while(c>='0'&&c<='9') {x=x*10+c-'0'; c=getchar();} return x*f; } void add(int from,int to) { cnt++; e[cnt].to=to; e[cnt].next=head[from]; head[from]=cnt; } void dfs(int x) { vis[x]=true; for(int i=head[x];i;i=e[i].next) { int now=e[i].to; if(!vis[now]) { depth[now]=depth[x]+1; f[now][0]=x; dfs(now); } } } void init() { for(int j=1;j<=N;j++) { for(int i=1;i<=n;i++) f[i][j]=f[f[i][j-1]][j-1]; } } int lca(int x,int y) { if(depth[x]>depth[y]) swap(x,y); int d=depth[y]-depth[x]; for(int i=0;i<=N;i++) { if((1<<i) & d) y=f[y][i]; } if(x==y) return x; for(int i=N;i>=0;i--) { if(f[x][i]!=f[y][i]) { x=f[x][i]; y=f[y][i]; } } return f[x][0]; } int main() { n=Read();m=Read();s=Read(); N=log(n)/log(2)+1; for(int i=1;i<n;i++) { int x,y; x=Read();y=Read(); add(x,y); add(y,x); } dfs(s); init(); while(m--) { int x,y; x=Read();y=Read(); printf("%d\n",lca(x,y)); } return 0; }
据我所知LCA的算法不只一种,比如:
ST表算法
Tarjan算法
树链剖分算法
倍增法只是其中一种在线算法,但已经够用
其他算法请小伙伴们自行查阅吧!
大图预警!!!
镇楼
来源:https://www.cnblogs.com/widerg/p/7349705.html