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 模板树链剖分的主要内容,如果未能解决你的问题,请参考以下文章