zoukankan      html  css  js  c++  java
  • [bzoj3626][LNOI2014]LCA

    Description

    给出一个\(n\)个节点的有根树(编号为\(0\)\(n-1\),根节点为\(0\))。

    一个点的深度定义为这个节点到根的距离\(+1\)

    \(dep[i]\)表示点\(i\)的深度,\(lca(i,j)\)表示\(i,j\)的最近公共祖先。

    \(q\)次询问,每次询问给出\(l\;r\;z\),求\(\sum_{i=l}^{r}dep[lca(i,z)]\)

    (即求在\([l,r]\)区间内的每个节点\(i\)\(z\)的最近公共祖先的深度之和)

    Input

    第一行\(2\)个整数\(n,q\)
    接下来\(n-1\)行,分别表示点\(1\)到点\(n-1\)的父节点编号。
    接下来\(q\)行,每行\(3\)个整数\(l\;r\;z\)

    Output

    输出\(q\)行,每行表示一个询问的答案。每个答案对\(201314\)取模输出。

    Sample Input

    5 2 
    0 
    0 
    1 
    1 
    1 4 3 
    1 4 2
    

    Sample Output

    8 
    5
    

    HINT

    \(n,q\;\leq\;50000\)

    Solution

    对于两个点\(x,y\),求\(dep[lca(x,y)]\),可以将\(x\)到根上的点全部打标记,求\(y\)向上第一个有标记的点的深度.

    即,将\(x\)到根的路径上的点点权设为\(1\),求\(y\)到根的路径权值和.

    \(0\)\(1\)依次插入点\(x\),将\(x\)到根的路径上的点点权\(+1\).

    离线处理类似前缀和的方式处理每个询问.

    #include<cmath>
    #include<ctime>
    #include<queue>
    #include<stack>
    #include<cstdio>
    #include<vector>
    #include<cstring>
    #include<cstdlib>
    #include<iostream>
    #include<algorithm>
    #define N 50005
    #define M 201314
    #define K 150005 
    using namespace std;
    struct graph{
        int nxt,to;
    }e[N];
    struct quest{
        int x,z,n,ans;
    }l[N],r[N];
    struct linetree{
        int l,r,s,len,lzy;
    }lt[K];
    int g[N],n,q,t1,t2,cnt;
    int f[N],p[N],dep[N],top[N],siz[N],son[N]; 
    inline int read(){
        int ret=0;char c=getchar();
        while(!isdigit(c))
            c=getchar();
        while(isdigit(c)){
            ret=(ret<<1)+(ret<<3)+c-'0';
            c=getchar();
        }
        return ret;
    }
    inline void addedge(int x,int y){
        e[++cnt].nxt=g[x];g[x]=cnt;e[cnt].to=y;
    }
    inline void dfs1(int u){
        int m=0;siz[u]=1;
        for(int i=g[u];i;i=e[i].nxt){
            f[e[i].to]=u;
            dep[e[i].to]=dep[u]+1;
            dfs1(e[i].to);
            siz[u]+=siz[e[i].to];
            if(siz[e[i].to]>m){
                son[u]=e[i].to;
                m=siz[e[i].to];
            }
        } 
    }
    inline void dfs2(int u,int tp){
        top[u]=tp;p[u]=++cnt;
        if(son[u]) dfs2(son[u],tp);
        for(int i=g[u];i;i=e[i].nxt)
            if(e[i].to!=son[u])
                dfs2(e[i].to,e[i].to);
    }
    inline void build(int u,int l,int r){
        lt[u].l=l;lt[u].r=r;lt[u].len=lt[u].r-lt[u].l+1;
        if(lt[u].l<lt[u].r){
            int lef=u<<1,rig=u<<1|1;
            int mid=lt[u].l+lt[u].r>>1;
            build(lef,l,mid);build(rig,mid+1,r);
        }
    }
    inline int cover(int u,int l,int r){
        if(lt[u].l>=l&&lt[u].r<=r){
            ++lt[u].lzy;
            lt[u].s=(lt[u].s+lt[u].len)%M;
        }
        else if(lt[u].l<lt[u].r){
            int lef=u<<1,rig=u<<1|1;
            int mid=lt[u].l+lt[u].r>>1;
            if(lt[u].lzy){
                lt[lef].lzy+=lt[u].lzy;
                lt[rig].lzy+=lt[u].lzy;
                lt[lef].s=(lt[lef].s+lt[lef].len*lt[u].lzy)%M;
                lt[rig].s=(lt[rig].s+lt[rig].len*lt[u].lzy)%M;
                lt[u].lzy=0;
            } 
            if(l<=mid) cover(lef,l,r);
            if(r>mid) cover(rig,l,r);
            lt[u].s=(lt[lef].s+lt[rig].s)%M;
        }
    }
    inline int ask(int u,int l,int r){
        if(lt[u].l>=l&&lt[u].r<=r)
            return lt[u].s;
        if(lt[u].l<lt[u].r){
            int lef=u<<1,rig=u<<1|1,ret=0;
            int mid=lt[u].l+lt[u].r>>1;
            if(lt[u].lzy){
                lt[lef].lzy+=lt[u].lzy;
                lt[rig].lzy+=lt[u].lzy;
                lt[lef].s=(lt[lef].s+lt[lef].len*lt[u].lzy)%M;
                lt[rig].s=(lt[rig].s+lt[rig].len*lt[u].lzy)%M;
                lt[u].lzy=0;
            } 
            if(l<=mid) ret=(ret+ask(lef,l,r))%M;
            if(r>mid) ret=(ret+ask(rig,l,r))%M;
            return ret;
        }
    }
    inline void add(int x,int y){
        int t;
        while(top[x]!=top[y]){
            if(dep[top[x]]<dep[top[y]]){
                t=x;x=y;y=t;
            }
            cover(1,p[top[x]],p[x]);
            x=f[top[x]];
        }
        if(p[x]>p[y]){
            t=x;x=y;y=t;
        }
        cover(1,p[x],p[y]); 
    }
    inline int que(int x,int y){
        int ret=0,t;
        while(top[x]!=top[y]){
            if(dep[top[x]]<dep[top[y]]){
                t=x;x=y;y=t;
            }
            ret=(ret+ask(1,p[top[x]],p[x]))%M;
            x=f[top[x]];
        }
        if(p[x]>p[y]){
            t=x;x=y;y=t;
        }
        ret=(ret+ask(1,p[x],p[y]))%M; 
        return ret;
    }
    inline bool cmp1(quest x,quest y){
        return x.x<y.x;
    }
    
    inline bool cmp2(quest x,quest y){
        return x.n<y.n;
    }
    inline void Aireen(){
        n=read();q=read();
        for(int i=2,j;i<=n;++i){
            j=read()+1;addedge(j,i);
        }
        for(int i=1;i<=q;++i){
            l[i].n=r[i].n=i;
            l[i].x=read();
            r[i].x=read()+1;
            l[i].z=r[i].z=read()+1;
        }
        sort(l+1,l+1+q,cmp1);
        sort(r+1,r+1+q,cmp1);
        while(t1<=q&&!l[t1].x) ++t1;
        while(t2<=q&&!r[t2].x) ++t2;
        dep[1]=1;dfs1(1);
        cnt=0;dfs2(1,1);
        build(1,1,n);
        for(int i=1;i<=n;++i){
            add(1,i);
            while(t1<=q&&l[t1].x==i){
                l[t1].ans=que(1,l[t1].z);++t1;
            }
            while(t2<=q&&r[t2].x==i){
                r[t2].ans=que(1,r[t2].z);++t2;
            }
        }
        sort(l+1,l+1+q,cmp2);
        sort(r+1,r+1+q,cmp2);
        for(int i=1;i<=q;++i)
            printf("%d\n",(r[i].ans-l[i].ans+M)%M);
    }
    int main(){
        freopen("lca.in","r",stdin);
        freopen("lca.out","w",stdout);
        Aireen();
        fclose(stdin);
        fclose(stdout);
        return 0;
    }
  • 相关阅读:
    Splay模板(bzoj 1588)
    PDD----配对堆
    [BZOJ4025] 二分图 LCT/(线段树分治+并查集)
    FFT模板 生成函数 原根 多项式求逆 多项式开根
    [BZOJ4566][Haoi2016]找相同字符 后缀自动机+dp
    [BZOJ1503] [NOI2004]郁闷的出纳员 splay
    [loj#2566][BZOJ5333] [Sdoi2018]荣誉称号 树形dp
    [BZOJ4824][Cqoi2017]老C的键盘 树形dp+组合数
    [BZOJ5305][Haoi2018]苹果树 组合数
    [BZOJ2669][cqoi2012]局部极小值 状压dp+容斥原理
  • 原文地址:https://www.cnblogs.com/AireenYe/p/bzoj3626.html
Copyright © 2011-2022 走看看