洛谷P4211/LOJ2558/BZOJ3626[LNOI2014]LCA(树链剖分+差分)

首先这个$dep[LCA(i,z)]$肯定不能直接求,考虑把它转化,发现$dep[LCA(i,z)]$就等于把$i$到根的路径上的点涂黑后,$z$到根路径上黑点的个数。推而广之,$(l,r,z)$对应的答案就是对于所有$l\le i\le r$的$i$,将$i$到根的路径上的点权值+1后$z$到根的权值和。

然后考虑如何维护这个东西。路径加+路径求和可以树剖,对询问区间右端点排序后可以只插入一次,然后用可持久化数据结构然后差分,把$(l,r,z)$转化为$(1,r,z)-(1,l-1,z)$就可以做到$O(nlog^2n)$了。

#include<cstdio>
#include<algorithm>
using namespace std;
typedef long long ll;
const int mod=201314;
const int N=50005;
char rB[1<<21],*rS,*rT,wB[1<<21];
int wp=-1;
inline char gc(){return rS==rT&&(rT=(rS=rB)+fread(rB,1,1<<21,stdin),rS==rT)?EOF:*rS++;}
inline void flush(){fwrite(wB,1,wp+1,stdout);wp=-1;}
inline void pc(char c){if(wp+1==(1<<21))flush();wB[++wp]=c;}
inline int rd(){
    char c=gc();
    while(c<48||c>57)c=gc();
    int x=c&15;
    for(c=gc();c>=48&&c<=57;c=gc())x=(x<<3)+(x<<1)+(c&15);
    return x;
}
short buf[15];
inline void wt(int x){
    short l=-1;
    while(x>9){
        buf[++l]=x%10;
        x/=10;
    }
    pc(x|48);
    while(l>=0)pc(buf[l--]|48);
    pc('\n');
}
int G[N],to[N],nxt[N],cnt=0,f[N],sz[N],dep[N],son[N],top[N],id[N],dfsc=0,sum[N<<2],addv[N<<2],n,r[N<<1];
struct query{
    int r,z,s;
}a[N<<1];
inline bool cmp(int x,int y){return a[x].r<a[y].r;}
inline void add(int u,int v){
    to[++cnt]=v;nxt[cnt]=G[u];G[u]=cnt;
}
void dfs1(int u,int fa){
    int i,v,maxn=0;
    dep[u]=dep[f[u]=fa]+1;
    sz[u]=1;
    for(i=G[u];i;i=nxt[i]){
        dfs1(v=to[i],u);
        sz[u]+=sz[v];
        if(sz[v]>maxn)maxn=sz[son[u]=v];
    }
}
void dfs2(int u,int topf){
    int i,v;
    top[u]=topf;
    id[u]=++dfsc;
    if(!son[u])return;
    dfs2(son[u],topf);
    for(i=G[u];i;i=nxt[i])if((v=to[i])!=son[u])dfs2(v,v);
}
void add(int o,int L,int R,int x,int y){
    if(x<=L&&y>=R){++addv[o];if((sum[o]+=R-L+1)>=mod)sum[o]-=mod;}
    else{
        int lc=o<<1,rc=lc|1,M=L+R>>1;
        if(x<=M)add(lc,L,M,x,y);
        if(y>M)add(rc,M+1,R,x,y);
        sum[o]=(sum[lc]+sum[rc]+(ll)addv[o]*(R-L+1))%mod;
    }
}
int ask(int o,int L,int R,int x,int y){
    if(x<=L&&y>=R)return sum[o];
    int lc=o<<1,rc=lc|1,M=L+R>>1,ans=(ll)addv[o]*(min(y,R)-max(x,L)+1)%mod;
    if(x<=M&&(ans+=ask(lc,L,M,x,y))>=mod)ans-=mod;
    if(y>M&&(ans+=ask(rc,M+1,R,x,y))>=mod)ans-=mod;
    return ans;
}
inline void Add(int u){
    while(u){
        add(1,1,n,id[top[u]],id[u]);
        u=f[top[u]];
    }
}
inline int Ask(int u){
    int ans=0;
    while(u){
        if((ans+=ask(1,1,n,id[top[u]],id[u]))>=mod)ans-=mod;
        u=f[top[u]];
    }
    return ans;
}
int main(){
    int q,i,j=1;
    n=rd();q=rd();
    for(i=2;i<=n;++i)add(rd()+1,i);
    dfs1(1,0);
    dfs2(1,1);
    for(i=0;i<q;++i){a[i<<1|1].r=rd();a[i<<1].r=rd()+1;a[i<<1].z=a[i<<1|1].z=rd()+1;r[i<<1]=i<<1;r[i<<1|1]=i<<1|1;}
    sort(r,r+(q<<1),cmp);
    for(i=0;i<(q<<1);++i){
        for(;j<=a[r[i]].r;++j)Add(j);
        a[r[i]].s=Ask(a[r[i]].z);
    }
    for(i=0;i<q;++i)wt((a[i<<1].s-a[i<<1|1].s+mod)%mod);
    flush();
    return 0;
}
View Code

 

posted @ 2019-08-02 14:05  wangyuchen  阅读(190)  评论(0编辑  收藏  举报