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
    ",(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;
    }
  • 相关阅读:
    Centos搭建SVN服务器
    JavaScript 对象 之创建对象 学习笔记
    ThinkPHP 学习记录
    Git 版本控制 在 WIN 下的一些使用方法
    关于 CSS 的重用性
    双飞翼布局和圣杯布局
    cocos2dx3.8 ios打包脚本编写
    如何做dragonbones的lua绑定(xcode)
    【转】如何做dragonbones的lua绑定(Android)
    【转】如何做dragonbones的lua绑定(VisualStudio)
  • 原文地址:https://www.cnblogs.com/AireenYe/p/6250013.html
Copyright © 2011-2022 走看看