P3379 【模板】最近公共祖先(LCA)

挂一波版

①rmq

先跑出欧拉序列,并求出每个点在欧拉序列中最先出现的位置pos。

然后两点的lca就是对应的pos之间的最小值。

#include<cstdio>
#include<cstring>
#include<iostream>
#include<vector>
#include<algorithm>
#include<set>
#include<map>
using namespace std;
#define rep(i,j,k) for(i=j;i<=k;++i)
#define per(i,j,k) for(i=j;i>=k;--i)
#define G getchar()
#define LL long long
#define pll pair<int,int>
#define mkp make_pair
#define X first
#define Y second
const int N=500005;
int n,m,rt;
int tot,he[N],ne[N<<1],to[N<<1];
int phi[N<<1],pos[N],ln,dep[N];
int Min[N<<1][21],cs,bit[N<<1];
void read(int &x){
	char ch=G;
	while(ch<48||ch>57)ch=G;
	for(x=0;ch>47&&ch<58;ch=G)x=x*10+ch-48;
}
void add(int x,int y){
	to[++tot]=y;ne[tot]=he[x];he[x]=tot;
}
void DFS(int x){
	int i,y;phi[pos[x]=++ln]=x;
	for(i=he[x];i;i=ne[i])if(!pos[y=to[i]]){
		dep[y]=dep[x]+1;DFS(y);phi[++ln]=x;
	}
}
int get(int i,int j){
	if(i>j)swap(i,j);
	int t=bit[j-i+1];
	int u=Min[i][t],v=Min[j-(1<<t)+1][t];
	return dep[u]<dep[v]?u:v;
}
int main(){
	int i,x,y,t;
	for(x=2,t=1;x<1000000;x<<=1)bit[x]=t++;
	rep(x,3,1000000)if(!bit[x])bit[x]=bit[x-1];
	read(n);read(m);read(rt);tot=1;
	rep(i,2,n){
		read(x);read(y);
		add(x,y);add(y,x);
	}
	dep[rt]=1;DFS(rt);
	per(i,ln,1){
		Min[i][0]=phi[i];
		for(t=1;ln-i+1>=(1<<t);cs=max(cs,t++)){
			x=i+(1<<t-1);
			Min[i][t]=dep[Min[i][t-1]]<dep[Min[x][t-1]]?Min[i][t-1]:Min[x][t-1];
		}
			
	}
	while(m--){
		read(x);read(y);
		printf("%d\n",get(pos[x],pos[y]));
	}
	return 0;
}

②倍增

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
#define rep(i,j,k) for(i=j;i<=k;++i)
#define per(i,j,k) for(i=j;i>=k;--i)
#define sqr(x) (x)*(x)
#define G getchar()
#define mkp make_pair
#define X first
#define Y second
#define LL long long
#define N 500005
int n,rt;
int he[N],ne[N<<1],to[N<<1],tot;
int dad[N][20],dep[N],cs;
int read(){
    int x=0;char ch=G;bool flg=0;
    while(ch!=45&&(ch<48||ch>57))ch=G;
    if(ch==45)flg=1,ch=G;
    for(;ch>47&&ch<58;ch=G)x=x*10+ch-48;
    return x;
}
void add(int x,int y){
    to[++tot]=y;ne[tot]=he[x];he[x]=tot;
}
void DFS(int x,int e){
    int i,y,t;
    for(t=1;y=dad[dad[x][t-1]][t-1];cs=max(cs,t++))dad[x][t]=y;
    for(i=he[x];i;i=ne[i])if(i!=e){
        dad[y=to[i]][0]=x;dep[y]=dep[x]+1;DFS(y,i^1);
    }
}
int lca(int x,int y){
    if(x==y)return x;
    if(dep[x]<dep[y])swap(x,y);
    int t;
    per(t,cs,0)if(dep[dad[x][t]]>=dep[y])x=dad[x][t];
    if(x==y)return x;
    per(t,cs,0)if(dad[x][t]!=dad[y][t])x=dad[x][t],y=dad[y][t];
    return dad[x][0];
}
int main(){
    int _,i,x,y;
    n=read();_=read();rt=read();
    tot=1;rep(i,2,n){
        x=read();y=read();add(x,y);add(y,x);
    }
    dep[rt]=1;DFS(rt,0);
    while(_--){
        x=read();y=read();
        printf("%d\n",lca(x,y));
    }
    return 0;
}

③树剖

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
#define rep(i,j,k) for(i=j;i<=k;++i)
#define per(i,j,k) for(i=j;i>=k;--i)
#define sqr(x) (x)*(x)
#define G getchar()
#define mkp make_pair
#define X first
#define Y second
#define LL long long
#define N 500005
int n,rt;
int he[N],ne[N<<1],to[N<<1],tot;
int dep[N],sz[N],dad[N],pre[N],son[N];
int read(){
    int x=0;char ch=G;bool flg=0;
    while(ch!=45&&(ch<48||ch>57))ch=G;
    if(ch==45)flg=1,ch=G;
    for(;ch>47&&ch<58;ch=G)x=x*10+ch-48;
    return x;
}
void add(int x,int y){
    to[++tot]=y;ne[tot]=he[x];he[x]=tot;
}
void DFS1(int x,int e){
    int i,y;sz[x]=1;
    for(i=he[x];i;i=ne[i])if(i!=e){
        pre[y=to[i]]=x;dep[y]=dep[x]+1;DFS1(y,i^1);
        sz[x]+=sz[y];if(sz[y]>sz[son[x]])son[x]=y;
    }
}
void DFS2(int x,int e){
    int i,y=pre[x];
    dad[x]=son[y]==x?dad[y]:x;
    for(i=he[x];i;i=ne[i])if(i!=e)
        DFS2(to[i],i^1);
}
int lca(int x,int y){
    int fx=dad[x],fy=dad[y];
    while(fx!=fy)
        if(dep[fx]>dep[fy])fx=dad[x=pre[fx]];
        else fy=dad[y=pre[fy]];
    return dep[x]>dep[y]?y:x;
}
int main(){
    int _,i,x,y;
    n=read();_=read();rt=read();
    tot=1;rep(i,2,n){
        x=read();y=read();add(x,y);add(y,x);
    }
    dep[rt]=1;DFS1(rt,0);DFS2(rt,0);
    while(_--){
        x=read();y=read();
        printf("%d\n",lca(x,y));
    }
    return 0;
}

④tarjan

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
#define rep(i,j,k) for(i=j;i<=k;++i)
#define per(i,j,k) for(i=j;i>=k;--i)
#define sqr(x) (x)*(x)
#define G getchar()
#define mkp make_pair
#define X first
#define Y second
#define LL long long
#define N 500005
int n,m,rt;
int he[N],ne[N<<1],to[N<<1],tot;
int heq[N],neq[N<<1],toq[N<<1],totq,ans[N];int par[N];
int read(){
	int x=0;char ch=G;bool flg=0;
	while(ch!=45&&(ch<48||ch>57))ch=G;
	if(ch==45)flg=1,ch=G;
	for(;ch>47&&ch<58;ch=G)x=x*10+ch-48;
	return x;
}
void add(int x,int y){
	to[++tot]=y;ne[tot]=he[x];he[x]=tot;
}
void addq(int x,int y){
	toq[++totq]=y;neq[totq]=heq[x];heq[x]=totq;
}
int getpar(int x){
	if(par[x]!=x)par[x]=getpar(par[x]);
	return par[x];
}
void DFS(int x,int e){
	int i,y;
	par[x]=x;
	for(i=heq[x];i;i=neq[i])
		if(par[y=toq[i]])ans[i>>1]=getpar(y);
	for(i=he[x];i;i=ne[i])if(i!=e){
		DFS(y=to[i],i^1);par[y]=x;
	}
}
int main(){
	int i,x,y;
	n=read();m=read();rt=read();
	tot=totq=1;rep(i,2,n){
		x=read();y=read();add(x,y);add(y,x);
	}
	rep(i,1,m){
		x=read();y=read();addq(x,y);addq(y,x);
	}
	DFS(rt,0);
	rep(i,1,m)printf("%d\n",ans[i]);
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值