UOJ Logo zgjkt的博客

博客

【bzoj3626】LCA

2017-03-16 13:42:49 By zgjkt

题目大意

给出一棵$n$个节点的有根树,编号为$0$到$n-1$,根节点为$0$

询问$m$次,每次询问给出区间$[l,r]$和节点编号$z$,求$$\sum_{l\leqslant i\leqslant r}deep[lca(i,z)]$$

每个答案对$201314$取模输出

数据范围

共$5$组数据,$n$与$m$的规模分别为$10000,20000,30000,40000,50000$


题解

http://blog.csdn.net/popoqqq/article/details/38823457

http://blog.csdn.net/alan_cty/article/details/51649011


程序

#include<cstdio>
#include<cmath>
#include<cstring>
#include<cctype>
#include<algorithm>
#define lp p<<1
#define rp p<<1|1
#define mod 201314
#define N 50500
#define For(i,l,r) for(int i=l;i<=r;++i)
#define goedge(i,x) for(int i=last[x];i;i=e[i].next)
inline int read(){
    int x=0;char ch=getchar();
    while (!isdigit(ch)) ch=getchar();
    while (isdigit(ch)) {x=x*10+ch-48;ch=getchar();}
    return x;
}
using namespace std;

int n,m,et,cnt;
int size[N],f[N],deep[N],top[N],pos[N];
struct edge{int to,next;}e[N];
struct answer{int z,ans1,ans2;}q[N];
struct data{int id,pos;bool flag;}a[2*N];
struct seg{int sum,tag;}t[4*N];
int last[N];

inline bool cmp(data a,data b){
    return a.pos<b.pos;
}
inline void addedge(int u,int v){
    e[++et]=(edge){v,last[u]};last[u]=et;
}
inline void pushdown(int p,int wl,int wr){
    if (wl==wr || !t[p].tag) return;
    int tmp=t[p].tag,mid=(wl+wr)>>1;t[p].tag=0;
    t[lp].sum+=(mid-wl+1)*tmp,t[rp].sum+=(wr-mid)*tmp;
    t[lp].tag+=tmp;t[rp].tag+=tmp;
}

void dfs(int x){
    size[x]=1;
    goedge(i,x){
        if (e[i].to==f[x]) continue;
        deep[e[i].to]=deep[x]+1;
        f[e[i].to]=x;
        dfs(e[i].to);
        size[x]+=size[e[i].to];
    }
}
void gochain(int x,int chain){
    top[x]=chain;pos[x]=++cnt;
    int k=n;
    goedge(i,x)
        if (e[i].to!=f[x] && size[e[i].to]>size[k]) k=e[i].to;
    if (k!=n) gochain(k,chain);
    goedge(i,x)
        if (e[i].to!=f[x] && e[i].to!=k) gochain(e[i].to,e[i].to);
}

void update(int p,int wl,int wr,int l,int r){
    pushdown(p,wl,wr);
    if (wl==l && wr==r){
        t[p].tag++,t[p].sum+=wr-wl+1;
        return;
    }
    int mid=(wl+wr)>>1;
    if (l<=mid) update(lp,wl,mid,l,min(mid,r));
    if (r>mid) update(rp,mid+1,wr,max(mid+1,l),r);
    t[p].sum=t[lp].sum+t[rp].sum;
}
inline void solve_update(int x,int y){
    while (top[x]!=top[y]){
        update(1,1,n,pos[top[x]],pos[x]);
        x=f[top[x]];
    }
    update(1,1,n,pos[y],pos[x]);
}
int query(int p,int wl,int wr,int l,int r){
    pushdown(p,wl,wr);
    if (wl==l && wr==r) return t[p].sum;
    int mid=(wl+wr)>>1;
    int s1=0,s2=0;
    if (l<=mid) s1=query(lp,wl,mid,l,min(mid,r));
    if (r>mid) s2=query(rp,mid+1,wr,max(mid+1,l),r);
    return s1+s2;
}
inline int solve_query(int x,int y){
    int sum=0;
    while (top[x]!=top[y]){
        sum=(sum+query(1,1,n,pos[top[x]],pos[x]))%mod;
        x=f[top[x]];
    }
    sum=(sum+query(1,1,n,pos[y],pos[x]))%mod;
    return sum;
}

int main(){
    n=read(),m=read();
    For(i,1,n-1){
        int u=read();
        addedge(u,i);
    }
    For(i,1,m){
        int l=read(),r=read();
        q[i].z=read();
        a[2*i-1]=(data){i,l-1,0};
        a[2*i]=(data){i,r,1};
    }
    sort(a+1,a+2*m+1,cmp);
    dfs(0);gochain(0,0);
    int now=-1;
    For(i,1,2*m){
        while (now<a[i].pos){
            now++;
            solve_update(now,0);
        }
        if (!a[i].flag) q[a[i].id].ans1=solve_query(q[a[i].id].z,0);
        else q[a[i].id].ans2=solve_query(q[a[i].id].z,0);
    }
    For(i,1,m)
        printf("%d\n",(q[i].ans2-q[i].ans1+mod)%mod);
    return 0;
}

评论

暂无评论

发表评论

可以用@mike来提到mike这个用户,mike会被高亮显示。如果你真的想打“@”这个字符,请用“@@”。