dfs序+线段树入门题

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);
    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值