【模板】树链剖分

#include<bits/stdc++.h> #define int long long using namespace std; const int N=200005; inline int read() { int X=0; bool flag=1; char ch=getchar(); while(ch<'0'||ch>'9') {if(ch=='-') flag=0; ch=getchar();} while(ch>='0'&&ch<='9') {X=(X<<1)+(X<<3)+ch-'0'; ch=getchar();} if(flag) return X; return ~(X-1); } int n,m,rt,mod,a[N],b[N]; int head[N],nxt[N],to[N],_cnt; int siz[N],fa[N],dep[N],son[N],tp[N],dfn[N],rnk[N],num; void add(int x,int y) { to[++_cnt]=y,nxt[_cnt]=head[x],head[x]=_cnt; } struct SegmentTree { int sum,len,dat; }t[N<<4]; void popup(int p) { t[p].sum=(t[p*2].sum+t[p*2+1].sum)%mod; } void pushdown(int p) { t[p*2].sum=(t[p*2].sum+t[p].dat*t[p*2].len%mod)%mod; t[p*2+1].sum=(t[p*2+1].sum+t[p].dat*t[p*2+1].len%mod)%mod; t[p*2].dat=(t[p*2].dat+t[p].dat)%mod; t[p*2+1].dat=(t[p*2+1].dat+t[p].dat)%mod; t[p].dat=0; } void build(int p,int l,int r) { t[p].len=r-l+1; if(l==r) { t[p].sum=a[l]; return; } int mid=(l+r)>>1; build(p*2,l,mid); build(p*2+1,mid+1,r); popup(p); } int query(int p,int l,int r,int ql,int qr) { if(ql<=l&&r<=qr) return t[p].sum; pushdown(p); int mid=(l+r)>>1,ans=0; if(ql<=mid) ans=(ans+query(p*2,l,mid,ql,qr))%mod; if(mid<qr) ans=(ans+query(p*2+1,mid+1,r,ql,qr))%mod; return ans; } void update(int p,int l,int r,int ql,int qr,int x) { if(ql<=l&&r<=qr) { t[p].dat=(t[p].dat+x)%mod; t[p].sum=(t[p].sum+t[p].len*x%mod)%mod; return; } pushdown(p); int mid=(l+r)>>1; if(ql<=mid) update(p*2,l,mid,ql,qr,x); if(mid<qr) update(p*2+1,mid+1,r,ql,qr,x); popup(p); } void dfs1(int x,int fath,int deep) { dep[x]=deep,fa[x]=fath,siz[x]=1; int maxson=-1; for(int i=head[x];i;i=nxt[i]) { int y=to[i]; if(y==fath) continue; dfs1(y,x,deep+1); siz[x]+=siz[y]; if(siz[y]>maxson) maxson=siz[y],son[x]=y; } } void dfs2(int x,int topf) { dfn[x]=++num,a[num]=b[x],tp[x]=topf; //pay attention if(!son[x]) return; dfs2(son[x],topf); for(int i=head[x];i;i=nxt[i]) { int y=to[i]; if(!dfn[y]) dfs2(y,y); } } int querysum(int x,int y) { int ans=0,fx=tp[x],fy=tp[y]; while(fx!=fy) { if(dep[fx]>=dep[fy]) ans=(ans+query(1,1,n,dfn[fx],dfn[x])),x=fa[fx]; else ans=(ans+query(1,1,n,dfn[fy],dfn[y]))%mod,y=fa[fy]; fx=tp[x],fy=tp[y]; } if(dfn[x]<dfn[y]) ans=(ans+query(1,1,n,dfn[x],dfn[y]))%mod; else ans=(ans+query(1,1,n,dfn[y],dfn[x]))%mod; return ans; } void queryadd(int x,int y,int z) { int fx=tp[x],fy=tp[y]; while(fx!=fy) { if(dep[fx]>=dep[fy]) update(1,1,n,dfn[fx],dfn[x],z),x=fa[fx]; else update(1,1,n,dfn[fy],dfn[y],z),y=fa[fy]; fx=tp[x],fy=tp[y]; } if(dfn[x]<dfn[y]) update(1,1,n,dfn[x],dfn[y],z); else update(1,1,n,dfn[y],dfn[x],z); } signed main() { n=read(),m=read(),rt=read(),mod=read(); for(int i=1;i<=n;i++) b[i]=read()%mod; for(int i=1;i<n;i++) { int x=read(),y=read(); add(x,y),add(y,x); } dfs1(rt,0,1); dfs2(rt,rt); build(1,1,n); for(int i=1;i<=m;i++) { int type=read(); if(type==1) { int x=read(),y=read(),z=read(); queryadd(x,y,z%mod); } else if(type==2) { int x=read(),y=read(); printf("%lld\n",querysum(x,y)); } else if(type==3) { int x=read(),z=read(); update(1,1,n,dfn[x],dfn[x]+siz[x]-1,z%mod); } else if(type==4) { int x=read(); printf("%lld\n",query(1,1,n,dfn[x],dfn[x]+siz[x]-1)); } } }

__EOF__

本文作者仰望星空的蚂蚁
本文链接https://www.cnblogs.com/cqbzly/p/17530365.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   仰望星空的蚂蚁  阅读(5)  评论(0编辑  收藏  举报  
编辑推荐:
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 没有源码,如何修改代码逻辑?
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· DeepSeek 开源周回顾「GitHub 热点速览」
点击右上角即可分享
微信分享提示