LOADING

加载过慢请开启缓存 浏览器默认开启

lca与树上(路径交、并,直径)问题

最近的一些比赛中经常用到树上lcalca的常见模型,整理一下:

首先整理一下LCALCA的四种求法:

1.倍增LCALCA:预处理O(nlogn)O(nlogn) 单次查询O(logn)O(logn)

通过bfsbfs预处理节点深度和stst表倍增处理祖宗节点,在查询的时候用倍增先将两点跳到统一深度,再找同祖宗节点的最深节点

int n,depth[N],f[N][19];
vector<int>e[N];
void bfs(int root){
	memset(depth,0x3f,sizeof depth);
	depth[0]=0,depth[root]=1;//0为st表的哨兵
	queue<int>q;
	q.push(root);
	while(q.size()){
		int ver=q.front();
		q.pop();
		for(auto &to:e[ver]){
			if(depth[to]>depth[ver]+1){
				depth[to]=depth[ver]+1;
				f[to][0]=ver;
				for(int i=1;i<=18;i++)
				f[to][i]=f[f[to][i-1]][i-1];
			}
		}
	}
}
int lca(int a,int b){
	if(depth[a]<depth[b])swap(a,b);
	for(int i=18;i>=0;i--){
		if(depth[f[a][i]]<=depth[b])
		a=f[a][i];
	}
	if(a==b)return a;
	for(int i=18;i>=0;i--){
		if(f[a][i]!=f[b][i])
		a=f[a][i],b=f[b][i];
	}
	return f[a][0];
}

2.TarjanTarjan离线LCALCA: 总体时间复杂度O(n+q)O(n+q)nn为节点 qq为查询次数

暂定

3.在线RMQLCARMQLCA:预处理O(nlogn)O(nlogn) 单次查询O(1)O(1)

通过dfsdfs处理欧拉序及其深度,并保存每个节点第一次出现位置,通过stst表维护区间深度最小值即可


int n,q,root,depth[N<<1],f[N<<1][19],se[N<<1],tot,Log[N<<1],id[N];
vector<int>e[N];
void dfs(int u,int d,int fa){
	se[++tot]=u;
	id[u]=tot;
	depth[tot]=d;
	for(auto &to:e[u]){
		if(to==fa)continue;
		dfs(to,d+1,u);
		se[++tot]=u;
		depth[tot]=d;
	}
}
int lca(int l,int r){
	int k=Log[r-l+1];
	return depth[f[l][k]]<depth[f[r-(1<<k)+1][k]]?
	se[f[l][k]]:se[f[r-(1<<k)+1][k]];
}
void solve(){
	cin>>n>>q>>root;
	for(int i=1;i<n;i++){
		int u,v;cin>>u>>v;
		e[u].pb(v);
		e[v].pb(u);
	}
	dfs(root,1,0);
	Log[1]=0,Log[2]=1;
	for(int i=3;i<=tot;i++)
	Log[i]=Log[i/2]+1;

	for(int i=1;i<=tot;i++)f[i][0]=i;

	for(int j=1;j<=Log[tot];j++)
	for(int i=1;i+(1<<j)-1<=tot;i++)
	if(depth[f[i][j-1]]<depth[f[i+(1<<(j-1))][j-1]])f[i][j]=f[i][j-1];
	else f[i][j]=f[i+(1<<(j-1))][j-1];
	
	while(q--){
		int u,v;cin>>u>>v;
		int l=id[u],r=id[v];
		if(l>r)swap(l,r);
	}
}

4.树链剖分LCALCA:预处理O(n)O(n) 单次查询O(logn)O(logn)

暂定

树上LCALCA的几种常用模型:

1.动态维护树的直径

2.树上路径的交

3.树上路径的并