树链剖分 (模板) 洛谷3384

题目描述

如题,已知一棵包含N个结点的树(连通且无环),每个节点上包含一个数值,需要支持以下操作:

操作1: 格式: 1 x y z 表示将树从x到y结点最短路径上所有节点的值都加上z

操作2: 格式: 2 x y 表示求树从x到y结点最短路径上所有节点的值之和

操作3: 格式: 3 x z 表示将以x为根节点的子树内所有节点值都加上z

操作4: 格式: 4 x 表示求以x为根节点的子树内所有节点值之和

输入输出格式

输入格式:
第一行包含4个正整数N、M、R、P,分别表示树的结点个数、操作个数、根节点序号和取模数(即所有的输出结果均对此取模)。

接下来一行包含N个非负整数,分别依次表示各个节点上初始的数值。

接下来N-1行每行包含两个整数x、y,表示点x和点y之间连有一条边(保证无环且连通)

接下来M行每行包含若干个正整数,每行表示一个操作,格式如下:

操作1: 1 x y z

操作2: 2 x y

操作3: 3 x z

操作4: 4 x

输出格式:
输出包含若干行,分别依次表示每个操作2或操作4所得的结果(对P取模)

输入输出样例

输入样例#1: 复制
5 5 2 24
7 3 7 8 0
1 2
1 5
3 1
4 1
3 4 2
3 2 2
4 5
1 5 1 3
2 1 3
输出样例#1: 复制
2
21
说明

时空限制:1s,128M

n<=10^5 , m<=10^5。

#include<iostream>
#include<cstdio>

using namespace std;
const int MAXN = 200005;

struct Edge{
    int nxt,to;
}edge[MAXN];

struct Node{
    int sum,lazy;
}node[MAXN*2];

int n,m,r,p,cnt,head[MAXN],w[MAXN],id[MAXN];
int d[MAXN],siz[MAXN],fa[MAXN],num;
int wt[MAXN],top[MAXN],res,son[MAXN];

inline void add(int bg,int ed){
    edge[++cnt].to=ed;
    edge[cnt].nxt=head[bg];
    head[bg]=cnt;
}

inline void dfs1(int x,int f,int deep){
    d[x]=deep;
    fa[x]=f;
    siz[x]=1;
    int maxson=-1;
    for(int i=head[x];i;i=edge[i].nxt){
        int u=edge[i].to;
        if(u==f) continue;
        dfs1(u,x,deep+1);
        siz[x]+=siz[u];
        if(siz[u]>maxson) son[x]=u,maxson=siz[u];
    } 
}

inline void dfs2(int x,int topf){
    id[x]=++num;
    wt[num]=w[x];
    top[x]=topf;
    if(!son[x]) return;
    dfs2(son[x],topf);
    for(int i=head[x];i;i=edge[i].nxt){
        int u=edge[i].to;
        if(u==fa[x] || u==son[x]) continue;
        dfs2(u,u);
    }
}

inline void pushdown(int rt,int len){
    node[rt<<1].sum+=node[rt].lazy*(len-(len>>1));
    node[rt<<1|1].sum+=node[rt].lazy*(len>>1);
    node[rt<<1].sum%=p;
    node[rt<<1|1].sum%=p;
    node[rt<<1].lazy+=node[rt].lazy;
    node[rt<<1|1].lazy+=node[rt].lazy;
    node[rt].lazy=0;        

}

inline void build(int rt,int l,int r){
    if(l==r){
        node[rt].sum=wt[l];
        if(node[rt].sum>p)
            node[rt].sum%=p;
        return; 
    } 
    int mid=(l+r)/2; 
    build(rt<<1,l,mid);
    build(rt<<1|1,mid+1,r);
    node[rt].sum=(node[rt<<1].sum+node[rt<<1|1].sum)%p;
} 

inline void update(int rt,int l,int r,int L,int R,int k){
    if(L<=l && r<=R){
        node[rt].sum+=(r-l+1)*k;
        node[rt].lazy+=k;
        return;
    }
    int mid=((l+r)>>1);
    if(node[rt].lazy) pushdown(rt,r-l+1);
    if(L<=mid) update(rt<<1,l,mid,L,R,k);
    if(R>mid) update(rt<<1|1,mid+1,r,L,R,k);
    node[rt].sum=(node[rt<<1].sum+node[rt<<1|1].sum)%p; 
}

inline void query(int rt,int l,int r,int L,int R){
    if(L<=l && r<=R){
        res+=node[rt].sum;
        res%=p;
        return;
    }
    int mid=(l+r)/2; 
    if(node[rt].lazy) pushdown(rt,r-l+1);
    if(L<=mid) query(rt<<1,l,mid,L,R);
    if(R>mid) query(rt<<1|1,mid+1,r,L,R);
}

inline void updRange(int x,int y,int k){
    k%=p;
    while(top[x]!=top[y]){
        if(d[top[x]]<d[top[y]]) swap(x,y);
        update(1,1,n,id[top[x]],id[x],k);
        x=fa[top[x]];
    }
    if(d[x]>d[y]) swap(x,y);
    update(1,1,n,id[x],id[y],k);
}

inline int qRange(int x,int y) {
    int ans=0;
    while(top[x]!=top[y]){
        if(d[top[x]]<d[top[y]]) swap(x,y);
        res=0;
        query(1,1,n,id[top[x]],id[x]);
        ans+=res;
        ans%=p;
        x=fa[top[x]];
    }
    if(d[x]>d[y]) swap(x,y);
    res=0;
    query(1,1,n,id[x],id[y]);
    ans+=res;
    return ans%p; 
}

inline void updSon(int x,int k){
    update(1,1,n,id[x],id[x]+siz[x]-1,k);
}

inline int qSon(int x){
    res=0;
    query(1,1,n,id[x],id[x]+siz[x]-1);
    return res;
}

int main() {
    scanf("%d%d%d%d",&n,&m,&r,&p);
    for(int i=1;i<=n;i++) scanf("%d",&w[i]);
    for(int i=1;i<n;i++){
        int a,b;
        scanf("%d%d",&a,&b);
        add(a,b);add(b,a); 
    }
    dfs1(r,0,1);
    dfs2(r,r);
    build(1,1,n);   
    while(m--){
        int k,x,y,z;
        scanf("%d",&k);
        if(k==1){
            scanf("%d%d%d",&x,&y,&z);
            updRange(x,y,z);
        }
        else if(k==2){
            scanf("%d%d",&x,&y);
            printf("%d
",qRange(x,y));
        }
        else if(k==3){
            scanf("%d%d",&x,&y);
            updSon(x,y);
        }
        else{
            scanf("%d",&x);
            printf("%d
",qSon(x));
        }
    }
    return 0;
}
原文地址:https://www.cnblogs.com/sdfzsyq/p/9677122.html