E. Company
题意:给你一颗树,有q次查询,每次查询一个区间[l,r],询问你删除其中的一个节点使得删除后节点的lca最大,输出要删除的节点和lca的深度。
题解:简单讲一下dfs序,其实就是你搜索树的先后顺序,然后这题你只要考虑一段区间dfs序最大和最小的节点会对lca产生影响,这很好理解,那么我们只需要用线段树维护一下这些点的dfs序,求个最大次大,最小次小,就解决了。
#include<bits/stdc++.h>
#define m (l+r)/2
#define ls o*2
#define rs o*2+1
using namespace std;
const int maxn = 1e5+10;
int f[maxn][20],d[maxn],id[maxn],rk[maxn],cnt=0;
vector<int>G[maxn];
void dfs(int u,int fa,int dep)
{
f[u][0] = fa;
d[u] = dep;
id[u] = ++cnt;
rk[cnt] = u;
for(int i=1;i<=18;i++)
f[u][i] = f[f[u][i-1]][i-1];
for(auto v:G[u])
if(v!=fa) dfs(v,u,dep+1);
}
int LCA(int u,int v)
{
if(d[u]<d[v]) swap(u,v);
for(int i=18;i>=0;i--)
if(d[f[u][i]]>=d[v])
u = f[u][i];
if(u==v) return d[u];
for(int i=18;i>=0;i--)
if(f[u][i]!=f[v][i])
u = f[u][i] , v = f[v][i];
return d[f[u][0]];
}
int tr_mx[maxn*4] , tr_mn[maxn*4];
void up(int o,int l,int r,int k,int p)
{
if(l==r){
tr_mn[o] = tr_mx[o] = p;
return ;
}
if(k>m) up(rs,m+1,r,k,p);
else up(ls,l,m,k,p);
tr_mx[o] = max(tr_mx[ls],tr_mx[rs]);
tr_mn[o] = min(tr_mn[ls],tr_mn[rs]);
}
int qu1(int o,int l,int r,int ql,int qr)
{
if(ql<=l&&qr>=r)return tr_mx[o];
int ans = -1e8;
if(ql<=m) ans = max(ans,qu1(ls,l,m,ql,qr));
if(qr>m) ans = max(ans,qu1(rs,m+1,r,ql,qr));
return ans ;
}
int qu2(int o,int l,int r,int ql,int qr)
{
if(ql<=l&&qr>=r) return tr_mn[o];
int ans = 1e8;
if(ql<=m) ans = min(ans,qu2(ls,l,m,ql,qr));
if(qr>m) ans = min(ans,qu2(rs,m+1,r,ql,qr));
return ans;
}
int main()
{
int v;
int n,q;scanf("%d%d",&n,&q);
for(int i=2;i<=n;i++)
{
scanf("%d",&v);
G[v].push_back(i);
G[i].push_back(v);
}
dfs(1,0,0);
for(int i=1;i<=n;i++)
up(1,1,n,i,id[i]);
int l,r;
for(int i=1;i<=q;i++)
{
scanf("%d%d",&l,&r);
int a1,a2,b1,b2;
a1 = qu1(1,1,n,l,r);
b1 = qu2(1,1,n,l,r);
up(1,1,n,rk[a1],-1e7);
a2 = qu1(1,1,n,l,r);
up(1,1,n,rk[a1],a1);
up(1,1,n,rk[b1],1e7);
b2 = qu2(1,1,n,l,r);
up(1,1,n,rk[b1],b1);
int lca1,lca2;
lca1 = LCA(rk[a1],rk[b2]) ,lca2=LCA(rk[a2],rk[b1]);
if(lca1>lca2)printf("%d %d\n",rk[b1],lca1);
else printf("%d %d\n",rk[a1],lca2);
}
}