挺好的一道树剖模板;
首先要学会最模板的树剖;
然后这道题要注意几个细节:
初始化时,seg[0]=1,seg[root]=1,top[root]=root,rev[1]=root;
在线段树上进行操作时,要使用lazy标记;
对于一个以x为根的子树,它子树中所有的元素一定时在线段树上连续的区间,且以seg[x]开始,以seg[x]+size[x]-1结束;
然后写码的时候注意不要手残(比如说预处理时写成了dep[u]=dep[u]+1);
#include <bits/stdc++.h> using namespace std; int n,m,r,p; int head[2000010],cnt; class littlestar{ public: int to; int nxt; void add(int u,int v){ to=v; nxt=head[u]; head[u]=cnt; } }star[2000010]; int a[100010]; int f[100010],dep[100010],son[100010],seg[100010],rev[100010],size[100010],top[100010]; void dfs1(int u,int fa) { size[u]=1; f[u]=fa; dep[u]=dep[fa]+1; for(int i=head[u];i;i=star[i].nxt){ int v=star[i].to; if(v==fa) continue; dfs1(v,u); size[u]+=size[v]; if(size[v]>size[son[u]]) son[u]=v; } } void dfs2(int u,int fa) { if(son[u]){ seg[son[u]]=++seg[0]; rev[seg[0]]=son[u]; top[son[u]]=top[u]; dfs2(son[u],u); } for(int i=head[u];i;i=star[i].nxt){ int v=star[i].to; if(v==fa) continue; if(!top[v]){ seg[v]=++seg[0]; rev[seg[0]]=v; top[v]=v; dfs2(v,u); } } } struct ss{ int sum; int lazy; }tree[1000010]; void build(int k,int l,int r) { if(l==r){ tree[k].sum=a[rev[l]]%p; return; } int mid=(l+r)/2; build(k<<1,l,mid); build(k<<1|1,mid+1,r); tree[k].sum=tree[k<<1].sum+tree[k<<1|1].sum; } void pre() { dfs1(r,0); seg[0]=seg[r]=1; top[r]=r; rev[1]=r; dfs2(r,0); build(1,1,seg[0]); } void pushdown(int k,int l,int r) { int mid=(l+r)/2; tree[k<<1].lazy=(tree[k<<1].lazy+tree[k].lazy)%p; tree[k<<1].sum=(tree[k<<1].sum+tree[k].lazy*(mid-l+1))%p; tree[k<<1|1].lazy=(tree[k<<1|1].lazy+tree[k].lazy)%p; tree[k<<1|1].sum=(tree[k<<1|1].sum+tree[k].lazy*(r-mid))%p; tree[k].lazy=0; } int query(int k,int l,int r,int x,int y) { if(r<x||l>y){ return 0; } if(l>=x&&r<=y){ return tree[k].sum%p; } int mid=(l+r)/2; pushdown(k,l,r); return (query(k<<1,l,mid,x,y)+query(k<<1|1,mid+1,r,x,y))%p; } void change(int k,int l,int r,int x,int y,int goal) { if(r<x||l>y) return; if(l>=x&&r<=y){ tree[k].sum=(tree[k].sum+(r-l+1)*goal)%p; tree[k].lazy=(tree[k].lazy+goal)%p; return; } pushdown(k,l,r); int mid=(l+r)/2; change(k<<1,l,mid,x,y,goal); change(k<<1|1,mid+1,r,x,y,goal); tree[k].sum=(tree[k<<1].sum+tree[k<<1|1].sum)%p; } void changeroad(int x,int y,int z) { int fx=top[x],fy=top[y]; while(fx!=fy){ if(dep[fx]<dep[fy]) swap(fx,fy),swap(x,y); change(1,1,seg[0],seg[fx],seg[x],z); x=f[fx]; fx=top[x]; } if(dep[x]>dep[y]) swap(x,y); change(1,1,seg[0],seg[x],seg[y],z); } int queryroad(int x,int y) { long long ans=0; int fx=top[x],fy=top[y]; while(fx!=fy){ if(dep[fx]<dep[fy]) swap(fx,fy),swap(x,y); ans=(ans+query(1,1,seg[0],seg[fx],seg[x]))%p; x=f[fx]; fx=top[x]; } if(dep[y]<dep[x]) swap(x,y); ans=(ans+query(1,1,seg[0],seg[x],seg[y]))%p; return ans%p; } void changetree(int x,int goal) { change(1,1,seg[0],seg[x],seg[x]+size[x]-1,goal); return; } long long querytree(int x) { long long res=0; res=(res+query(1,1,seg[0],seg[x],seg[x]+size[x]-1))%p; return res; } int main(){ cin>>n>>m>>r>>p; for(int i=1;i<=n;i++){ scanf("%d",&a[i]); } for(int i=1;i<=n-1;i++){ int u,v; scanf("%d%d",&u,&v); star[++cnt].add(u,v); star[++cnt].add(v,u); } pre(); for(int i=1;i<=m;i++){ int type; scanf("%d",&type); if(type==1){ int x,y,z; scanf("%d%d%d",&x,&y,&z); changeroad(x,y,z); } else if(type==2){ int x,y; scanf("%d%d",&x,&y); cout<<queryroad(x,y)%p<<endl; } else if(type==3){ int x,z; scanf("%d%d",&x,&z); changetree(x,z); } else{ int x; scanf("%d",&x); cout<<querytree(x)%p<<endl; } } } /* 5 5 2 30000 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 */