LCA进阶


1. 欧拉序+ST表

欧拉序求LCA
// Problem: P3379 【模板】最近公共祖先(LCA)
// Contest: Luogu
// URL: https://www.luogu.com.cn/problem/P3379
// Memory Limit: 512 MB
// Time Limit: 2000 ms
// 
// Powered by CP Editor (https://cpeditor.org)

#include <bits/stdc++.h>
#include <bits/extc++.h>
#define INF 0x7fffffff
#define MAXN 500002
#define MAXM 10003
#define eps 1e-9
#define foru(a,b,c)	for(int a=b;a<=c;a++)
#define ford(a,b,c)	for(int a=b;a>=c;a--)
#define RT return 0;
#define db(x)	cout<<endl<<x<<endl;
#define LL long long
#define LXF int
#define RIN rin()
#define HH printf("\n")
using namespace std;
inline LXF rin(){
	LXF x=0,w=1;
	char ch=0;
	while(ch<'0'||ch>'9'){ 
	if(ch=='-') w=-1;
	ch=getchar();
	}
	while(ch>='0'&&ch<='9'){
	x=x*10+(ch-'0');
	ch=getchar();
	}
	return x*w;
}
inline void out(LXF x){
	if(x<0){
	x=-x;
	putchar('-');
	}
	if(x>9) out(x/10);
	putchar(x%10+'0');
}
int n,m,s,cnt,to[MAXN];
struct N{
	int d,id;
}st[22][MAXN<<2];
bool operator < (const N &p,const N &q){
	return p.d<q.d;
}
vector<int> e[MAXN];
void dfs(int s,int fa,int dep){
	to[s]=++cnt;
	st[0][cnt]=(N){dep,s};
	for(int i=0;i<e[s].size();i++){
		int v=e[s][i];
		if(v!=fa){
			dfs(v,s,dep+1);
			st[0][++cnt]=(N){dep,s};
		}	
	}
}
int ask(int l,int r){
	int k=log2(r-l+1);
	return min(st[k][l],st[k][r-(1<<k)+1]).id;
}
int main(){
	n=RIN,m=RIN,s=RIN;
	foru(i,1,n-1){
		int u=RIN,v=RIN;
		e[u].push_back(v);
		e[v].push_back(u);
	}
	dfs(s,-1,1);
	for(int i=1;i<=21;i++){
		for(int j=1;j+(1<<i)-1<=cnt;j++){
			st[i][j]=min(st[i-1][j],st[i-1][j+(1<<(i-1))]);
		}
	}
	foru(i,1,m){
		int l=RIN,r=RIN;
		printf("%d\n",ask(min(to[l],to[r]),max(to[l],to[r])));
	}
	return 0;
}

2. 树链剖分求LCA

树剖求LCA
 // Problem: P3379 【模板】最近公共祖先(LCA)
// Contest: Luogu
// URL: https://www.luogu.com.cn/problem/P3379
// Memory Limit: 512 MB
// Time Limit: 2000 ms
// 
// Powered by CP Editor (https://cpeditor.org)

#include <bits/stdc++.h>
#include <bits/extc++.h>
#define INF 0x7fffffff
#define MAXN 500005
#define MAXM 500005
#define eps 1e-9
#define foru(a,b,c)	for(int a=b;a<=c;a++)
#define ford(a,b,c)	for(int a=b;a>=c;a--)
#define RT return 0;
#define db(x)	cout<<endl<<x<<endl;
#define LL long long
#define LXF int
#define RIN rin()
#define HH printf("\n")
using namespace std;
inline LXF rin(){
	LXF x=0,w=1;
	char ch=0;
	while(ch<'0'||ch>'9'){ 
	if(ch=='-') w=-1;
	ch=getchar();
	}
	while(ch>='0'&&ch<='9'){
	x=x*10+(ch-'0');
	ch=getchar();
	}
	return x*w;
}
inline void out(LXF x){
	if(x<0){
	x=-x;
	putchar('-');
	}
	if(x>9) out(x/10);
	putchar(x%10+'0');
}
int n,m,r,top[MAXN],dep[MAXN],cnt,fa[MAXN],siz[MAXN],son[MAXN],id[MAXN];
vector<int> e[MAXN];
void dfs1(int s,int fath){
	dep[s]=dep[fath]+1;
	fa[s]=fath;
	siz[s]=1;
	int maxson=-1;
	for(int i=0;i<e[s].size();i++){
		int v=e[s][i];
		if(v!=fath){
			dfs1(v,s);
			siz[s]+=siz[v];
			if(siz[v]>maxson){
				son[s]=v;
				maxson=siz[v];
			}
		}
	}
}
void dfs2(int s,int topf){
	id[s]=++cnt;
	top[s]=topf;
	if(!son[s])	return ;
	dfs2(son[s],topf);
	for(int i=0;i<e[s].size();i++){
		int v=e[s][i];
		if(v!=fa[s]&&v!=son[s]){
			dfs2(v,v);
		}
	}
}
int LCA(int x,int y){
	while(top[x]!=top[y]){
		if(dep[top[x]]<dep[top[y]])	swap(x,y);
		x=fa[top[x]];
	}
	if(dep[x]<dep[y])	swap(x,y);
	return y;
}
int main(){
	n=RIN,m=RIN,r=RIN;
	foru(i,1,n-1){
		int u=RIN,v=RIN;
		e[u].push_back(v);
		e[v].push_back(u);
	}
	dfs1(r,0);
	dfs2(r,r);
	while(m--){
		printf("%d\n",LCA(RIN,RIN));
	}
	return 0;
}

3. (离线) Tarjan算法求LCA

记得用前向星存树,vector会慢1.5s以上

Tarjan求LCA
 // Problem: P3379 【模板】最近公共祖先(LCA)
// Contest: Luogu
// URL: https://www.luogu.com.cn/problem/P3379
// Memory Limit: 512 MB
// Time Limit: 2000 ms
// 
// Powered by CP Editor (https://cpeditor.org)

#include <bits/stdc++.h>
#include <bits/extc++.h>
#define INF 0x7fffffff
#define MAXN 500005
#define MAXM 500005
#define eps 1e-9
#define foru(a,b,c)	for(int a=b;a<=c;a++)
#define ford(a,b,c)	for(int a=b;a>=c;a--)
#define RT return 0;
#define db(x)	cout<<endl<<x<<endl;
#define LL long long
#define LXF int
#define RIN rin()
#define HH printf("\n")
using namespace std;
inline LXF rin(){
	LXF x=0,w=1;
	char ch=0;
	while(ch<'0'||ch>'9'){ 
	if(ch=='-') w=-1;
	ch=getchar();
	}
	while(ch>='0'&&ch<='9'){
	x=x*10+(ch-'0');
	ch=getchar();
	}
	return x*w;
}
inline void out(LXF x){
	if(x<0){
	x=-x;
	putchar('-');
	}
	if(x>9) out(x/10);
	putchar(x%10+'0');
}
int n,m,r,jh[MAXN],ehead[MAXN],qhead[MAXN],ecnt,qcnt;
bool vis[MAXN];
int find(int x){
	return jh[x]==0?x:jh[x]=find(jh[x]);
}
struct E{
	int v,nxt,lca;
}e[MAXM<<1],q[MAXM<<1];
void tarjan(int s){
	vis[s]=1;
	for(int i=ehead[s];i;i=e[i].nxt){
		int v=e[i].v;
		if(!vis[v]){
			tarjan(v);
			jh[v]=find(s);
		}
	}
	for(int i=qhead[s];i;i=q[i].nxt){
		int v=q[i].v;
		if(vis[v]){
			if(i&1)	q[i].lca=q[i+1].lca=find(v);
			else	q[i].lca=q[i-1].lca=find(v);
		}
	}
}
void add_e(int u,int v){
	e[++ecnt]=(E){v,ehead[u],0};
	ehead[u]=ecnt;
}
void add_q(int u,int v){
	q[++qcnt]=(E){v,qhead[u],0};
	qhead[u]=qcnt;
}
int main(){
	n=RIN,m=RIN,r=RIN;
	foru(i,1,n-1){
		int u=RIN,v=RIN;
		add_e(u,v);
		add_e(v,u);
	}
	foru(i,1,m){
		int u=RIN,v=RIN;
		add_q(u,v);
		add_q(v,u);
	}
	tarjan(r);
	foru(i,1,m){
		printf("%d\n",q[i<<1].lca);
	}
	return 0;
}

总结

posted @ 2022-08-03 13:33  Cap1taL  阅读(32)  评论(0)    收藏  举报