6th 2022/6/8 算法总结·LCA·倍增

开头的话

这个算法对于大部分图论无环图题都是必备的,应多多复习

大概是对于两个点的公共祖先

倍增

众所周知,为了找到公共祖先,最暴力的算法就莫过于一个个往上跳,直至相遇

而倍增,就是一大步一大步跳

首先,设Fi,j

为从第i号店往上跳2j

很好转移吧,就是Fi,j=FFi,j1,j1

简单的思路,第2j

步就是两个2j1

然后一大步一大步跳即可

注意:若跳过头了,就是他们跳到一个地方去了啊

还需在最开始时,把他们弄到同一层去啊

只需化二进制他们深度之差后再把深度大的跳上来啊

树剖

需前置知识树链剖分

树剖打法,就是跑一遍树剖板子,然后你会发现,在跳链时,当他们在同一条链后,深度浅的就是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);
	}
}
posted @   Far_delivery  阅读(79)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示