树链剖分模板

#include<bits/stdc++.h>
using namespace std;
const int N=4e5+10;
typedef long long ll;
int n,m,r,p;
int id[N],w[N],pre[N],top[N],h[N],e[N],ne[N],idx,times;
int fa[N],sz[N],son[N],depth[N];
struct node{
    int l,r;
    ll sum;
    ll lazy;
}tr[N];
void add(int a,int b){
    e[idx]=b,ne[idx]=h[a],h[a]=idx++;
}
void dfs(int u){//算父亲和重儿子
    int i;
    sz[u]=1;
    for(i=h[u];i!=-1;i=ne[i]){
        int j=e[i];
        if(j==fa[u])
            continue;
        fa[j]=u;
        depth[j]=depth[u]+1;
        dfs(j);
        sz[u]+=sz[j];
        if(sz[j]>sz[son[u]]){
            son[u]=j;
        }
    }
}
void dfs1(int u,int x){
    pre[u]=++times;
    id[times]=u;
    top[u]=x;
    if(!son[u])
        return ;
    dfs1(son[u],x);
    for(int i=h[u];i!=-1;i=ne[i]){
        int j=e[i];
        if(j==son[u]||j==fa[u])
            continue;
        dfs1(j,j);
    }
}
void pushup(int u){
    tr[u].sum=(tr[u<<1].sum+tr[u<<1|1].sum)%p;
}
void build(int u,int l,int r){
    if(l==r){
        tr[u]={l,r,w[id[l]]%p,0};
    }
    else{
        tr[u]={l,r};
        int mid=l+r>>1;
        build(u<<1,l,mid);
        build(u<<1|1,mid+1,r);
        pushup(u);
    }
}
void pushdown(int u){
    auto & t=tr[u];
    auto & l=tr[u<<1];
    auto & r=tr[u<<1|1];
    if(t.lazy){
        l.lazy+=t.lazy;
        l.lazy%=p;
        l.sum+=(ll)(l.r-l.l+1)*t.lazy;
        l.sum%=p;
        r.lazy+=t.lazy;
        r.sum+=(ll)(r.r-r.l+1)*t.lazy;
        r.lazy%=p;
        r.sum%=p;
        t.lazy=0;
    }
}
void modify(int u,int l,int r,int d){
    if(tr[u].l>=l&&tr[u].r<=r){
        tr[u].sum+=(ll)(tr[u].r-tr[u].l+1)*d;
        tr[u].sum%=p;
        tr[u].lazy+=d;
        tr[u].lazy%=p;
    }
    else{
        pushdown(u);
        int mid=tr[u].l+tr[u].r>>1;
        if(l<=mid)
        modify(u<<1,l,r,d);
        if(r>mid)
        modify(u<<1|1,l,r,d);
        pushup(u);

    }
}
ll query(int u,int l,int r){
    if(tr[u].l>=l&&tr[u].r<=r)
    return tr[u].sum%p;
    else{
        pushdown(u);
        int mid=tr[u].l+tr[u].r>>1;
        ll res=0;
        if(l<=mid)
        res=query(u<<1,l,r);
        if(r>mid)
        res+=query(u<<1|1,l,r);
        return res;
    }
}
void uppath(int x,int y,int z){
    while(top[x]!=top[y]){
        if(depth[top[x]]<depth[top[y]])
            swap(x,y);
        modify(1,pre[top[x]],pre[x],z);
        x=fa[top[x]];
    }
    if(depth[x]>depth[y])
        swap(x,y);
    modify(1,pre[x],pre[y],z);
}

int qpath(int x,int y){
    int res=0;
    while(top[x]!=top[y]){
        if(depth[top[x]]<depth[top[y]])
            swap(x,y);
        res=(res+query(1,pre[top[x]],pre[x]))%p;
        x=fa[top[x]];
    }
    if(depth[x]>depth[y])
        swap(x,y);
    res=(res+query(1,pre[x],pre[y]))%p;
    return res;
}
void uptree(int x,int y){
    modify(1,pre[x],pre[x]+sz[x]-1,y);
}
int qtree(int x){
    //cout<<pre[x]<<" "<<pre[x]+sz[x]-1<<endl;
    return query(1,pre[x],pre[x]+sz[x]-1)%p;
}
int main(){
    ios::sync_with_stdio(false);
    cin>>n>>m>>r>>p;
    int i;
    memset(h,-1,sizeof h);
    for(i=1;i<=n;i++){
        cin>>w[i];
    }
    for(i=1;i<n;i++){
        int a,b;
        cin>>a>>b;
        add(a,b);
        add(b,a);
    }
    dfs(r);
    dfs1(r,r);
    build(1,1,n);
    while(m--){
        int opt;
        cin>>opt;
        int x,y,z;
        if(opt==1){
            cin>>x>>y>>z;
            uppath(x,y,z);
        }
        else if(opt==2){
            cin>>x>>y;
            cout<<qpath(x,y)<<endl;
        }
        else if(opt==3){
            cin>>x>>z;
            uptree(x,z);
        }
        else{
            cin>>x;
            cout<<qtree(x)<<endl;
        }
    }
}
View Code

 

posted @ 2020-05-27 14:37  朝暮不思  阅读(135)  评论(0编辑  收藏  举报