codeforces 1062E Company dfs序+线段树+lca

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/ccsu_cat/article/details/84104969

E. Company

题意:给你一颗树,有q次操作,每次操作询问一个区间 l r,你可以删除区间内任意一个节点,使得这个区间的lca最大,并输出删除的节点和区间lca。(每次操作独立不影响下一次操作)

思路:我们可以先在树上走一遍dfs序,每次询问的区间,决定lca的肯定是dfs序最大和最小的两个点,因此我们只要通过线段树找到区间内最小的la和次小的a,最大的rb和次大的b,然后比较lca(la,b)和lca(a,rb)就可以了。

#include<cstdio>
#include<algorithm>
#include<vector>
using namespace std;
const int maxn=1e5+10;
vector<int>G[maxn];
int anc[maxn][20],dep[maxn],n,cnt=0;
int mx[maxn*4],mn[maxn*4],id[maxn],s[maxn];
void dfs(int u,int fa,int deep)
{
	dep[u]=deep;
	anc[u][0]=fa;
	s[u]=++cnt;
	id[cnt]=u;
	for(int i=0;i<G[u].size();i++)
	dfs(G[u][i],u,deep+1);
}
void init()
{
	for(int j=1;j<19;j++)	
	for(int i=1;i<=n;i++)
	anc[i][j]=anc[anc[i][j-1]][j-1];
}
int lca(int p,int q)
{
	if(dep[p]<dep[q])swap(p,q);
	for(int i=18;i>=0;i--)
	if(dep[anc[p][i]]>=dep[q])
	p=anc[p][i];
	if(p==q)return dep[p]-1;
	for(int i=18;i>=0;i--)
	if(anc[p][i]!=anc[q][i])
	p=anc[p][i],q=anc[q][i];
	return dep[anc[p][0]]-1;
}
int qmax(int o,int l,int r,int ql,int qr)
{
	if(l>=ql&&r<=qr)return mx[o];
	int ls=o*2,rs=o*2+1,m=(l+r)/2,res=0;
	if(ql<=m)res=qmax(ls,l,m,ql,qr);
	if(qr>m)res=max(res,qmax(rs,m+1,r,ql,qr));
	return res;
}
int qmin(int o,int l,int r,int ql,int qr)
{
	if(l>=ql&&r<=qr)return mn[o];
	int ls=o*2,rs=o*2+1,m=(l+r)/2,res=1e8;
	if(ql<=m)res=qmin(ls,l,m,ql,qr);
	if(qr>m)res=min(res,qmin(rs,m+1,r,ql,qr));
	return res;
}
void up(int o,int l,int r,int k,int v)
{
	if(l==r)
	{
		mx[o]=mn[o]=v;
		return;
	}
	int ls=o*2,rs=o*2+1,m=(l+r)/2;
	if(k<=m)up(ls,l,m,k,v);
	else up(rs,m+1,r,k,v);
	mx[o]=max(mx[ls],mx[rs]);
	mn[o]=min(mn[ls],mn[rs]);
}
int main()
{
	int q,x,l,r;
	scanf("%d%d",&n,&q);
	for(int i=2;i<=n;i++)
	{
		scanf("%d",&x);
		G[x].push_back(i);
	}
	dfs(1,0,1);
	init();
	for(int i=1;i<=n;i++)
	up(1,1,n,i,s[i]);
	while(q--)
	{
		scanf("%d%d",&l,&r);
		int la=qmin(1,1,n,l,r);
		int rb=qmax(1,1,n,l,r);
		up(1,1,n,id[la],1e8);
		int a=qmin(1,1,n,l,r);
		up(1,1,n,id[la],la);
		up(1,1,n,id[rb],0);
		int b=qmax(1,1,n,l,r);
		up(1,1,n,id[rb],rb);
		int t1=lca(id[la],id[b]),t2=lca(id[a],id[rb]);
		if(t1>=t2)
		printf("%d %d\n",id[rb],t1);
		else printf("%d %d\n",id[la],t2);
	}
}

猜你喜欢

转载自blog.csdn.net/ccsu_cat/article/details/84104969