6th 2022/6/8 算法总结·LCA·倍增
开头的话
这个算法对于大部分图论无环图题都是必备的,应多多复习
大概是对于两个点的公共祖先
倍增
众所周知,为了找到公共祖先,最暴力的算法就莫过于一个个往上跳,直至相遇
而倍增,就是一大步一大步跳
首先,设
为从第i号店往上跳
很好转移吧,就是
简单的思路,第
步就是两个
然后一大步一大步跳即可
注意:若跳过头了,就是他们跳到一个地方去了啊
还需在最开始时,把他们弄到同一层去啊
只需化二进制他们深度之差后再把深度大的跳上来啊
树剖
需前置知识树链剖分
树剖打法,就是跑一遍树剖板子,然后你会发现,在跳链时,当他们在同一条链后,深度浅的就是LCA
树剖LCA常数小,且好打得多
推荐
总结
在打这个时,出现了初始化问题
还需注意和复习
代码(展示倍增)
#include<cstdio>
#include<cmath>
using namespace std;
int n,m,root;
int bz[500001];
int *a[500001],len[500001];
int l[500001],r[500001],x,y,max_deep=1;
int jump_binary[100001],len_binary;
int father[500001],deep[500001],f[500001][21];
int ans;
void swap(int &a,int &b){
int g=a;a=b;b=g;
}
int max(int x,int y){
return x>y?x:y;
}
int pow(int x,int y){
int h=1;
for(int i=1;i<=y;i++){
h*=x;
}
return h;
}
void build_tree(int x){
bz[x]=1;
for(int i=1;i<=a[x][0];i++){
if(bz[a[x][i]]==1){
a[x][i]=-1;
continue;
}
build_tree(a[x][i]);
}
}
void get(int x,int delta,int fath){
father[x]=fath;
deep[x]=delta;
for(int i=1;i<=a[x][0];i++){
if(a[x][i]==-1){
continue;
}
max_deep=max(max_deep,deep[x]);
get(a[x][i],delta+1,x);
}
}
void get_f(int x,int i_f){
int len_f=pow(2,i_f);
if(x!=root){
if(i_f==0){
f[x][0]=father[x];
}
else{
if(deep[x]>len_f){
f[x][i_f]=f[f[x][i_f-1]][i_f-1];
}
}
}
for(int i=1;i<=a[x][0];i++){
if(a[x][i]==-1){
continue;
}
get_f(a[x][i],i_f);
}
}
void turn_into_binary(int x){
while(x>0){
jump_binary[++len_binary]=x%2;
x/=2;
}
}
int get_LCA(int x,int y){
int distance;
if(deep[x]!=deep[y]){
if(deep[x]<deep[y]){
swap(x,y);
}
len_binary=0;
turn_into_binary(distance);
for(int i=len_binary;i>=1;i--){
int now_binary=len_binary-i+1;
if(jump_binary[now_binary]==1){
x=f[x][now_binary-1];
}
}
}
int w=log2(max_deep);
if(x==y){
return x;
}
if(father[x]==father[y]){
return father[x];
}
while(f[x][w]==0||f[y][w]==0||f[x][w]==f[y][w]||father[f[x][w]]!=father[f[y][w]]){
if(x==0||y==0){
return root;
}
if(f[x][w]==f[y][w]&&w>0){
w--;
}
else{
x=f[x][w];
y=f[y][w];
if(father[x]==father[y]&&f[x][w]!=f[y][w]){
return father[x];
}
}
}
x=f[x][w];
y=f[y][w];
return father[x];
}
int main(){
scanf("%d%d%d",&n,&m,&root);
for(int i=1;i<n;i++){
scanf("%d%d",&l[i],&r[i]);
len[l[i]]++;
len[r[i]]++;
}
for(int i=1;i<=n;i++){
a[i]=new int[len[i]+1];
a[i][0]=0;
}
for(int i=1;i<n;i++){
a[l[i]][++a[l[i]][0]]=r[i];
a[r[i]][++a[r[i]][0]]=l[i];
}
build_tree(root);
get(root,1,-1);
int log2n=log2(max_deep);
for(int i=0;i<=log2n;i++){
get_f(root,i);
}
for(int i=1;i<=m;i++){
scanf("%d%d",&x,&y);
ans=get_LCA(x,y);
printf("%d\n",ans);
}
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】