BZOJ3626 神思路的树链剖分+线段树维护

给清华爷的思路跪了 想了N久  觉得可以深度建树开二维的来维护标记...然而N->50000数组存不下  看了别人的题解....原来可以用线段树离线操作对于这个点的深度贡献对于经过的每个节点+1 类似于前缀和的操作 然后对于操作离散化(嗯 最关键的操作就是把深度贡献 均分给他经过的节点上....至于为什么 可以手动画一画  然后想明白这个就发现只是树剖的基本操作 进行区间更新和区间查询即可

3626: [LNOI2014]LCA

Time Limit: 10 Sec  Memory Limit: 128 MB
Submit: 3482  Solved: 1365
[Submit][Status][Discuss]

Description

给出一个n个节点的有根树(编号为0到n-1,根节点为0)。一个点的深度定义为这个节点到根的距离+1。
设dep[i]表示点i的深度,LCA(i,j)表示i与j的最近公共祖先。
有q次询问,每次询问给出l r z,求sigma_{l<=i<=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
/**************************************************************
    Problem: 3626
    User: wang9897
    Language: C++
    Result: Accepted
    Time:2288 ms
    Memory:8776 kb
****************************************************************/
 
#include <bits/stdc++.h>
#define N 50005
#define lth 201314
using namespace std;
int son[N],num[N],fa[N],dep[N];
int p[N],fp[N],tp[N],cnt,n,q;
vector<int>vec[N];
int read(){
    int x=0,f=1;char ch=getchar();
    while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
    while(isdigit(ch))x=x*10+ch-'0',ch=getchar();
    return f*x;
}
void dfs1(int v,int pre,int deep){
    num[v]=1;fa[v]=pre;dep[v]=deep+1;
    for(int i=0;i<vec[v].size();i++){
        if(vec[v][i]!=pre){
            dfs1(vec[v][i],v,deep+1);
            num[v]+=num[vec[v][i]];
            if(son[v]==-1||num[vec[v][i]]>num[son[v]]){
                son[v]=vec[v][i];
            }
        }
    }
}
void dfs2(int v,int td){
    p[v]=++cnt;fp[cnt]=v;tp[v]=td;
    if(son[v]!=-1) dfs2(son[v],td);
    for(int i=0;i<vec[v].size();i++){
        if(vec[v][i]!=fa[v]&&vec[v][i]!=son[v]) dfs2(vec[v][i],vec[v][i]);
    }
}
typedef struct node{
    int l,r,sum,flag;
}node;
node d[N<<2];
void push(int x){
    if(d[x].flag){
        d[x<<1].sum=(d[x<<1].sum+(1ll*d[x].flag*(d[x<<1].r-d[x<<1].l+1))%lth)%lth;d[x<<1|1].sum=(d[x<<1|1].sum+(1ll*d[x].flag*(d[x<<1|1].r-d[x<<1|1].l+1))%lth)%lth;
        d[x<<1].flag=(d[x<<1].flag+d[x].flag)%lth;d[x<<1|1].flag=(d[x<<1|1].flag+d[x].flag)%lth;
        d[x].flag=0;
    }
}
void up(int x){
    d[x].sum=(d[x<<1].sum+d[x<<1|1].sum)%lth;
}
void built(int rt,int l,int r){
    if(l==r){
        d[rt].l=d[rt].r=l;d[rt].flag=d[rt].sum=0;
        return ;
    }
    int mid=(l+r)>>1;
    built(rt<<1,l,mid);
    built(rt<<1|1,mid+1,r);
    d[rt].l=d[rt<<1].l;d[rt].r=d[rt<<1|1].r;d[rt].flag=0;
    up(rt);
}
void update(int root,int l,int r){
    if(l<=d[root].l&&d[root].r<=r){
        d[root].flag+=1;d[root].sum=(d[root].sum+(d[root].r-d[root].l+1)%lth)%lth;
        return ;
    }
    push(root);
    int mid=(d[root].l+d[root].r)>>1;
    if(l<=mid) update(root<<1,l,r);
    if(r>mid) update(root<<1|1,l,r);
    up(root);
}
int ans;
void querty(int root,int l,int r){
    if(l<=d[root].l&&d[root].r<=r){
        ans+=d[root].sum;
        return ;
    }
    int mid=(d[root].l+d[root].r)>>1;
    push(root);
    if(l<=mid) querty(root<<1,l,r);
    if(r>mid) querty(root<<1|1,l,r);
    up(root);
}
int Sum(int v,int t){
    int ans1=0;int vv=tp[v];
    while(vv!=1){
        if(t==1) update(1,p[vv],p[v]);
        else{
            ans=0;querty(1,p[vv],p[v]);
            ans1=(ans1+ans)%lth;
        }
        v=fa[vv];vv=tp[v];
    }
    if(t==1) update(1,1,p[v]);
    else{
        ans=0;querty(1,1,p[v]);
        ans1=(ans1+ans)%lth;
    }
    return ans1;
}
typedef struct List{
    int l,wei,z;
    friend bool operator <(List aa,List bb){
        return aa.l<bb.l;
    }
}List;
List dd[N<<1];
int ans2[N];
int main(){
    ios::sync_with_stdio(false);
    scanf("%d%d",&n,&q);cnt=0;
    int t;
    for(int i=1;i<=n;i++) son[i]=-1;
    for(int i=2;i<=n;i++){
        scanf("%d",&t);
        vec[t+1].push_back(i);
    }
    int x,y,z;int cnt1=0;
    memset(ans2,0,sizeof(ans2));
    for(int i=1;i<=q;i++){
        scanf("%d %d %d",&x,&y,&z);
        dd[++cnt1].l=x;dd[cnt1].wei=i;dd[cnt1].z=z+1;
        dd[++cnt1].l=y+1;dd[cnt1].wei=i;dd[cnt1].z=z+1;
    }
    sort(dd+1,dd+cnt1+1);
    dfs1(1,0,0);
//  cout<<"sb"<<endl;
    dfs2(1,1);
    built(1,1,n);int u=1;
    for(int i=1;i<=cnt1;i++){
        if(dd[i].l==0) continue;
        while(u<=dd[i].l){
            Sum(u,1);u++;
        }
    //  Sum(u,1);
        int tt=Sum(dd[i].z,0);
        //cout<<dd[i].l<<" "<<dd[i].wei<<" "<<tt<<endl;
        ans2[dd[i].wei]=((tt-ans2[dd[i].wei])%lth+lth)%lth;
    }
    for(int i=1;i<=q;i++) printf("%d\n",ans2[i]);
    return 0;
}

 

posted @ 2018-01-31 17:08  wang9897  阅读(167)  评论(0编辑  收藏  举报