【题目】:给你一颗由n个点组成的树,编号为1-n中的一个数字,并且各不相同。一共有q个询问,每次询问给你一个区间[L,R],让你求出在可以忽略区间中一个点的情况下,他们深度最大的lca是谁,并且输出忽略的是谁,lca是谁。
链接:E. Company
【题解】:结论:对这棵树进行dfs序,然后一个区间的LCA一定是dfs序最小的点和dfs序最大的点的LCA。
证明挺简单的 这里忽略。
那么知道了这个结论之后我们只要先用线段树维护好区间最小的和最大的dfs序,每次询问到一个区间时,把dfs序最大的点拿掉,然后找第二大的点,求它和dfs序最小的点的lca,然后再把第一大的点放回来,再把第一小的点拿掉,再找到第二小的点和第一大的点求LCA,把两个答案进行比较后输出答案即可。
【代码】:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll maxn = 100000+30;
int cnt=1,head[maxn],E[maxn*2];
struct Node
{
int u,v,w,nxt;
}node[maxn*2];
void add(int u,int v,int w)
{
node[cnt].u=u;
node[cnt].v=v;
node[cnt].w=w;
node[cnt].nxt=head[u];
head[u]=cnt++;
}
int dfn[maxn],dep[maxn],st[maxn*2][25];
void dfs(int rt,int fa,int d)
{
dfn[rt]=++cnt;
E[cnt]=rt;
dep[rt]=d;
for(int i=head[rt];i;i=node[i].nxt){
dfs(node[i].v,rt,d+1);
E[++cnt]=rt;
}
}
void buildST()
{
for(int i=1;i<=cnt;i++){
st[i][0]=E[i];
}
for(int i=1;i<=24;i++){
for(int j=1;j<=cnt;j++){
if(j+(1<<i)-1>cnt) break;
if(dep[st[j][i-1]]<dep[st[j+(1<<(i-1))][i-1]]) st[j][i]=st[j][i-1];
else st[j][i]=st[j+(1<<(i-1))][i-1];
}
}
}
int lca(int a,int b)
{
int x=a,y=b;
if(x>y) swap(x,y);
int j=1;
int cnt=0;
while(j*2<=y-x+1){
j<<=1;
cnt++;
}
if(dep[st[x][cnt]]<dep[st[y-j+1][cnt]]) return st[x][cnt];
else return st[y-j+1][cnt];
}
int maxP[maxn*8],minP[maxn*8];
void build(int rt,int L,int R)
{
if(L==R){
maxP[rt]=dfn[L];
minP[rt]=dfn[L];
}
else{
int mid=L+R>>1;
build(rt<<1,L,mid);
build(rt<<1|1,mid+1,R);
maxP[rt]=max(maxP[rt<<1],maxP[rt<<1|1]);
minP[rt]=min(minP[rt<<1],minP[rt<<1|1]);
}
}
int queryMax(int rt,int L,int R,int l,int r)
{
if(L>=l&&R<=r) return maxP[rt];
int mid=L+R>>1;
if(mid>=r){
return queryMax(rt<<1,L,mid,l,r);
}
else if(mid<l){
return queryMax(rt<<1|1,mid+1,R,l,r);
}
else{
return max(queryMax(rt<<1,L,mid,l,mid),queryMax(rt<<1|1,mid+1,R,mid+1,r));
}
}
int queryMin(int rt,int L,int R,int l,int r)
{
if(L>=l&&R<=r) return minP[rt];
int mid=L+R>>1;
if(mid>=r){
return queryMin(rt<<1,L,mid,l,r);
}
else if(mid<l){
return queryMin(rt<<1|1,mid+1,R,l,r);
}
else{
return min(queryMin(rt<<1,L,mid,l,mid),queryMin(rt<<1|1,mid+1,R,mid+1,r));
}
}
void update(int rt,int L,int R,int v,int x)
{
if(L==R){
maxP[rt]=minP[rt]=v;
}
else{
int mid=L+R>>1;
if(x<=mid){
update(rt<<1,L,mid,v,x);
}
else{
update(rt<<1|1,mid+1,R,v,x);
}
maxP[rt]=max(maxP[rt<<1],maxP[rt<<1|1]);
minP[rt]=min(minP[rt<<1],minP[rt<<1|1]);
}
}
int main()
{
//printf("%d\n",1<<25);
int n,q,x;
scanf("%d%d",&n,&q);
for(int i=2;i<=n;i++){
scanf("%d",&x);
add(x,i,1);
}
cnt=0;
dfs(1,0,0);
buildST();
build(1,1,cnt);
int l,r;
for(int i=0;i<q;i++){
scanf("%d%d",&l,&r);
int a=queryMax(1,1,cnt,l,r);
int b=queryMin(1,1,cnt,l,r);
int p1=E[a],p2=E[b];
update(1,1,cnt,0,p1);
int t=queryMax(1,1,cnt,l,r);
int ans1=lca(t,b);
update(1,1,cnt,a,p1);
update(1,1,cnt,maxn*100,p2);
t=queryMin(1,1,cnt,l,r);
int ans2=lca(t,a);
update(1,1,cnt,b,p2);
if(dep[ans1]>dep[ans2]){
printf("%d %d\n",p1,dep[ans1]);
}
else{
printf("%d %d\n",p2,dep[ans2]);
}
}
return 0;
}