CF1062E Company

线段树,树状数组,dfn序,lca

题意

给定一颗树,有若干个询问,每个询问给出 \(l\) ,\(r\),要求编号在 \([l,r]\) 中的点任意删去一个之后剩余点的 LCA 深度最大,输出删去点的编号和 LCA 的最大深度。

\(1\le n,m\le 10^5\).

题解

显然,对于区间 \([l,r]\),删除的数一定是 \(dfn\) 的最大或最小值。

用st表和线段树简单维护即可。

代码

#include<bits/stdc++.h>
#define ls (p<<1)
#define rs (p<<1|1)
#define mid (l+r>>1)
// #define int long long
using namespace std;
const int Maxn=1e5+10;
int n,q,cnt;
int nxt[Maxn][22];
int dep[Maxn],dfn[Maxn];
int f[4*Maxn];
int mx[Maxn][22],mn[Maxn][22],lg[Maxn];
vector<int>edge[Maxn];
void dfs(int u,int fa=0)
{
    dfn[u]=++cnt;
    mx[u][0]=mn[u][0]=u;
    for(int v:edge[u]) if(v!=fa)
    {
        dep[v]=dep[u]+1;
        dfs(v);
    }
}
int query_mx(int l,int r)
{
    int k=lg[r-l+1];
    return (dfn[mx[l][k]]>dfn[mx[r-(1<<k)+1][k]]?mx[l][k]:mx[r-(1<<k)+1][k]);
}
int query_mn(int l,int r)
{
    int k=lg[r-l+1];
    return (dfn[mn[l][k]]<dfn[mn[r-(1<<k)+1][k]]?mn[l][k]:mn[r-(1<<k)+1][k]);
}
int lca(int u,int v)
{
    if(dep[u]<dep[v]) swap(u,v);
    if(!v) return u;
    for(int i=20;i>=0;i--) if(dep[nxt[u][i]]>=dep[v]) u=nxt[u][i];
    if(u==v) return u;
    for(int i=20;i>=0;i--) if(nxt[u][i]!=nxt[v][i]) u=nxt[u][i],v=nxt[v][i];
    return nxt[u][0];
}
void push_up(int p) {f[p]=lca(f[ls],f[rs]);}
void change(int p,int l,int r,int tar)
{
    if(l==r) return f[p]=tar,void();
    if(tar<=mid) change(ls,l,mid,tar);
    else change(rs,mid+1,r,tar);
    push_up(p);
}
int query(int p,int l,int r,int tl,int tr)
{
    if(tr<tl) return 0;
    if(tl<=l && tr>=r) return f[p];
    if(tr<=mid) return query(ls,l,mid,tl,tr);
    if(tl>mid) return query(rs,mid+1,r,tl,tr);
    return lca(query(ls,l,mid,tl,tr),query(rs,mid+1,r,tl,tr));
}
signed main()
{
    cin>>n>>q; dep[0]=-1e9;
    for(int i=2;i<=n;i++)
    {
        cin>>nxt[i][0]; 
        edge[nxt[i][0]].push_back(i);
    }
    for(int i=2;i<=n;i++) lg[i]=lg[i>>1]+1;
    dfs(1);
    for(int j=1;j<=20;j++)
        for(int i=1;i<=n;i++)
            nxt[i][j]=nxt[nxt[i][j-1]][j-1];
    for(int j=1;j<=20;j++)
        for(int i=1;i+(1<<j)-1<=n;i++)
        {
            if(dfn[mx[i][j-1]]>dfn[mx[i+(1<<(j-1))][j-1]]) mx[i][j]=mx[i][j-1];
            else mx[i][j]=mx[i+(1<<(j-1))][j-1];
            if(dfn[mn[i][j-1]]<dfn[mn[i+(1<<(j-1))][j-1]]) mn[i][j]=mn[i][j-1];
            else mn[i][j]=mn[i+(1<<(j-1))][j-1];
        }
    for(int i=1;i<=n;i++) change(1,1,n,i);
    while(q--)
    {
        int l,r;
        cin>>l>>r;
        int p_mx=query_mx(l,r),p_mn=query_mn(l,r);
        int res_mx=lca(query(1,1,n,l,p_mx-1),query(1,1,n,p_mx+1,r)),res_mn=lca(query(1,1,n,l,p_mn-1),query(1,1,n,p_mn+1,r));
        if(dep[res_mx]<dep[res_mn]) cout<<p_mn<<" "<<dep[res_mn]<<endl;
        else cout<<p_mx<<" "<<dep[res_mx]<<endl;
    }
    return 0;
}
posted @ 2025-12-10 20:13  crazy--boy  阅读(3)  评论(0)    收藏  举报