luoguP3384 模板树链剖分

Posted dream-runner

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了luoguP3384 模板树链剖分相关的知识,希望对你有一定的参考价值。

树链剖分模板题,学习树链剖分推荐ppt

https://wenku.baidu.com/view/a088de01eff9aef8941e06c3.html?from=search

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+10;
typedef long long ll;
int dep[maxn],a[maxn],size[maxn],top[maxn],son[maxn],pos[maxn],f[maxn],n,m,root,head[maxn],cnt=0,sz=0;
ll lazy[maxn*4],MOD;
struct list{
    int l,r;
    ll sum;
}tree[maxn*4];
struct edge{
    int to,next;
}e[maxn*2];
void pushdown(int k){
    tree[k].sum=tree[k<<1].sum+tree[k<<1|1].sum;
}
void pushlazy(int k){
    if(lazy[k]){
        int l=tree[k].l,r=tree[k].r,mid=(l+r)>>1;
        tree[k<<1].sum+=(mid-l+1)*lazy[k];
        tree[k<<1|1].sum+=(r-mid)*lazy[k];
        lazy[k<<1]+=lazy[k];lazy[k<<1|1]+=lazy[k];
        lazy[k]=0;
    }
}
void add_edge(int s,int t){
    e[++cnt].next=head[s];e[cnt].to=t;head[s]=cnt;
    e[++cnt].next=head[t];e[cnt].to=s;head[t]=cnt;
}
void init(){
    scanf("%d%d%d%lld",&n,&m,&root,&MOD);
    for(int i=1;i<=n;++i)scanf("%d",&a[i]);
    for(int i=1;i<=n-1;++i){
        int s,t;
        scanf("%d%d",&s,&t);
        add_edge(s,t);
    }
}
void dfs1(int u){
    size[u]=1;
    for(int i=head[u];i;i=e[i].next){
        if(e[i].to!=f[u]){
            dep[e[i].to]=dep[u]+1;
            f[e[i].to]=u;
            dfs1(e[i].to);
            size[u]+=size[e[i].to];
        }
    }
}
void dfs2(int u,int chain){
    ++sz;pos[u]=sz;
    top[u]=chain;
    int k=0;
    for(int i=head[u];i;i=e[i].next){
        if(e[i].to!=f[u]&&size[e[i].to]>size[k]){
            k=e[i].to;
        }
    }
    if(k==0)return ;
    dfs2(k,chain);
    for(int i=head[u];i;i=e[i].next){
        if(e[i].to!=f[u]&&e[i].to!=k){
            dfs2(e[i].to,e[i].to);
        }
    }
}
void build(int k,int l,int r){
    tree[k].l=l;tree[k].r=r;
    if(l==r)return ;
    int mid=(l+r)>>1;
    build(k<<1,l,mid);
    build(k<<1|1,mid+1,r);
}
void change(int k,int tl,int tr,int x){
    pushlazy(k);
    int l=tree[k].l,r=tree[k].r,mid=(l+r)>>1;
    if(tl<=l&&tr>=r){
        tree[k].sum+=(r-l+1)*x;
        tree[k].sum%=MOD;
        lazy[k]+=x;
        return ;
    }
    if(mid>=tl)change(k<<1,tl,tr,x);
    if(mid<tr)change(k<<1|1,tl,tr,x);
    pushdown(k);
}
ll query(int k,int tl,int tr){
    pushlazy(k);
    int l=tree[k].l,r=tree[k].r,mid=(l+r)>>1;
    if(tl<=l&&tr>=r){
        return tree[k].sum;
    }
    ll ret=0;
    if(mid>=tl)ret+=query(k<<1,tl,tr);ret%=MOD;
    if(mid<tr)ret+=query(k<<1|1,tl,tr);ret%=MOD;
    return ret;
}
void change_sum(int x,int y,int z){
    while(top[x]!=top[y]){
        if(dep[top[x]]<dep[top[y]])swap(x,y);
        change(1,pos[top[x]],pos[x],z%MOD);
        x=f[top[x]];
    }
    if(dep[x]>dep[y])swap(x,y);
    change(1,pos[x],pos[y],z);
}
ll get_sum(int x,int y){
    ll ret=0;
    while(top[x]!=top[y]){
        if(dep[top[x]]<dep[top[y]])swap(x,y);
        ret+=query(1,pos[top[x]],pos[x]);
        x=f[top[x]];
        ret%=MOD;
    }
    if(dep[x]>dep[y])swap(x,y);
    ret+=query(1,pos[x],pos[y]);
    ret%=MOD;
    return ret;
}
void solve(){
    build(1,1,n);
    for(int i=1;i<=n;++i){
        change(1,pos[i],pos[i],a[i]);
    }
    for(int i=1;i<=m;++i){
        int opt;
        scanf("%d",&opt);
        if(opt==1){
            int x,y,z;
            scanf("%d%d%d",&x,&y,&z);
            change_sum(x,y,z);
        }
        else if(opt==2){
            int x,y;
            scanf("%d%d",&x,&y);
            printf("%lld
",get_sum(x,y));
        }
        else if(opt==3){
            int x,z;
            scanf("%d%d",&x,&z);
            change(1,pos[x],pos[x]+size[x]-1,z);
        }
        else if(opt==4){
            int x;
            scanf("%d",&x);
            printf("%lld
",query(1,pos[x],pos[x]+size[x]-1));
        }
    }
    return ;
}
int main(){
    init();
    dfs1(root);
    dfs2(root,root);
    solve();
    return 0;
}

 

以上是关于luoguP3384 模板树链剖分的主要内容,如果未能解决你的问题,请参考以下文章

「LuoguP3384」模板树链剖分

[luogu P3384] [模板]树链剖分

树链剖分模板题(luogu3384 模板树链剖分)

[洛谷P3384]模板树链剖分

P3384 模板树链剖分

P3384 模板树链剖分