• cf 1062e 区间lca+线段树+dfs序


    http://codeforces.com/contest/1062/problem/E

    题意:给出一棵有根树,1为根结点,接下来q次询问,每次给出一个[l,r]区间,

      现在允许删掉[l,r]区间内任何一个点,使得所有点的最近公共祖先的深度尽可能大,
      问删掉的点是哪个点,深度最大是多

    思路:

    区间lca的求法:

    区间的LCA等价于区间dfs序的最小值和最大值对应的两个点的LCA。

    (给定的一段点都可以..)

    证明:

    假设 r 是 这些点的lca , in[r]<=in[u]<=in[v]<=out[r]    (=是可能是一个点..)

    那么假设有w  in[u]<=in[w]<=in[v] 

    很明显  in[r]<=in[w]<=out[r]  所以w是r的子树上的点

    这就证明了

    所以用线段树 保存in[u]的最大值,最小值得到点

    在删除点的时候,假设u,v是最大和最小,那么在[l,r]删除除了u,v的其他点是无意义的

    所以也就是算   [l,u-1]U[u+1,r]  和 [l,v-1,v+1,r]  那个更符合条件了

    这样就是 线段树+区间Lca了

    #include<bits/stdc++.h>
    using namespace std;
    #define mem(a) memset(a,0,sizeof(a))
    #define time __tiem
    #define lson l,mid,rt<<1
    #define rson mid+1,r,rt<<1|1
    
    const int N= 1e5+4;
    struct edge{
        int x[N],y[N],z[N],cnt,nxt[N],fst[N];
        void clc(){
            cnt =0 ;
            mem(fst);
        }
        void add(int a,int b){
            x[++cnt] = a;
            y[cnt] = b;
            nxt[cnt] =fst[a];
            fst[a]= cnt;
        }
    }e;
    int n,m,depth[N],in[N],out[N],time;
    int ST[N*2][20];
    int tmax[N<<2],tmin[N<<2];
    int Hash[N<<2];
    
    //先保存最值  之后再Hash一下 得到点
    void pushup(int rt){
        tmin[rt] = min(tmin[rt<<1],tmin[rt<<1|1]);
        tmax[rt] = max(tmax[rt<<1],tmax[rt<<1|1]);
    }
    
    void build(int l,int r,int rt){
        if(l==r){
            tmin[rt] =tmax[rt]=  in[l];
            return ;
        }
        int mid = (l+r)>>1;
        build(lson);
        build(rson);
        pushup(rt);
    }
    int quemin(int l,int r,int rt,int a,int b){
        int mid =(l+r)>>1;
        int ans= 1e8+4;
        if(a>b)return ans;
        if(a<=l && b>=r)return min(ans,tmin[rt]);
        if(a<=mid) ans= min(ans, quemin(lson,a,b));
        if(b>mid) ans=  min(ans, quemin(rson,a,b  ));
        return ans ;
    }
    int  quemax(int l,int r,int rt,int a,int b){
        int ans= -1;
        if(a>b)return -1;
        int mid = (l+r)>>1;
        if(a<=l && b>=r)return max(ans,tmax[rt]);
        if(a<=mid) ans= max(ans, quemax(lson,a,b));
        if(b>mid) ans = max(ans, quemax(rson,a,b ) );
        return ans ;
    }
    
    void dfs(int t){
        in[t] = ++time;
        ST[time][0] =t;
        for(int i=e.fst[t];i;i=e.nxt[i]){
            depth[e.y[i]] = depth[t]+1;
            dfs(e.y[i]);
            ST[++time][0]=t;
        }
        out[t] =time;
    }
    void Get_ST(int n){
        for (int i=1;i<=n;i++)
            for (int j=1;j<20;j++){
                ST[i][j]=ST[i][j-1];
                int v=i-(1<<(j-1));
                if (v>0&&depth[ST[v][j-1]]<depth[ST[i][j]])
                    ST[i][j]=ST[v][j-1];
            }
    }
    int RMQ(int L,int R){
        int val=floor(log(R-L+1)/log(2));
        int x=ST[L+(1<<val)-1][val],y=ST[R][val];
        if (depth[x]<depth[y])
            return x;
        else
            return y;
    }
    
    int getmin(int a,int b,int c,int d){
        int res=quemin(1,n,1,a,b);
        return Hash[ min(res, quemin(1,n,1,c,d)) ];
    }
    int getmax(int a,int b,int c,int d){
        int res = quemax(1,n,1,a,b);
        return Hash[max(res,quemax(1,n,1,c,d))];
    }
    
    int main(){
        int q;
        scanf("%d %d",&n,&q);
        int x;
        for(int i=2;i<=n;++i){
            scanf("%d",&x);
            e.add(x,i);
        }
    
        dfs(1);
    
        Get_ST(time);
        build(1,n,1);
        for(int i=1;i<=n;++i){
            Hash[in[i]]=i;
        }
    
        while(q--){
           int l,r;
           scanf("%d %d",&l,&r);
            //区间Lca
            int u = quemin(1,n,1,l,r);
            int v = quemax(1,n,1,l,r);
            u = Hash[u];
            v = Hash[v];
    
            int Min = getmin(l,u-1,u+1,r);//(4,5) (7,6) --5
            int Max = getmax(l,v-1,v+1,r);//(4,3) (5,6) --** 5
    
            if(Min==-1 || Min>1e6)Min =v,cerr<<"??"<<endl;
            if(Max==-1 || Max>1e6)Max =u,cerr<<"??"<<endl;
    
            int lca1 = RMQ(in[Min],in[v]);
            int lca2=  RMQ(in[u],in[Max]);
    
            if(depth[lca1]>depth[lca2])printf("%d %d
    ",u,depth[lca1]);
            else printf("%d %d
    ",v,depth[lca2]);
        }
        return 0;
    }
  • 相关阅读:
    android -------- Data Binding的使用(二)
    牛客网-《剑指offer》-数值的整数次方[快速幂运算]
    牛客网-《剑指offer》-二进制中1的个数
    牛客网-《剑指offer》-矩形覆盖
    牛客网-《剑指offer》-变态跳台阶
    牛客网-《剑指offer》-跳台阶
    牛客网-《剑指offer》-斐波那契数列
    牛客网-《剑指offer》-旋转数组的最小数
    牛客网-《剑指offer》-用两个栈实现队列
    牛客网-《剑指offer》-重建二叉树
  • 原文地址:https://www.cnblogs.com/wjhstudy/p/9986069.html
Copyright © 2020-2023  润新知