[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;
}
posted @ 2017-01-04 19:38  Aireen_Ye  阅读(415)  评论(0编辑  收藏  举报
底部 顶部 留言板 归档 标签
Der Erfolg kommt nicht zu dir, du musst auf den Erfolg zugehen.