1. 程式人生 > >codeforces 1062E Company dfs序+線段樹+lca

codeforces 1062E Company dfs序+線段樹+lca

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);
	}
}