#include <bits/stdc++.h> #define DBG(x) cerr << #x << " = " << x << endl; const int maxn = 1e5+5; using namespace std; inline int read(){ int x=0,f=1;char ch=getchar(); while(ch < ‘0‘ || ch > ‘9‘){if(ch==‘-‘)f=-1;ch=getchar();} while(ch >= ‘0‘ && ch <= ‘9‘){x=x*10+ch-‘0‘;ch=getchar();} return x*f; } int n,m,rot,mod; int w[maxn],wt[maxn];///剖分前后的点权,不要抄错QAQ int head[maxn],tot; int cnt,dep[maxn],siz[maxn],fa[maxn],son[maxn],id[maxn],top[maxn];///son[i]表示i的重儿子,top[i]表示i所在链的顶点 int ans; struct treenode{ int l,r,val,add; }tree[maxn<<2]; struct edgenode{ int to,next; }edge[maxn<<1]; void addedge(int u,int v){ edge[tot].to=v; edge[tot].next=head[u]; head[u]=tot++; } void push_up(int x){ tree[x].val=tree[x<<1].val+tree[x<<1|1].val; tree[x].val%=mod; } void push_down(int x,int len){ if(tree[x].add){ tree[x<<1].add+=tree[x].add; tree[x<<1|1].add+=tree[x].add; tree[x<<1].val+=(len-(len>>1))*tree[x].add; tree[x<<1|1].val+=(len>>1)*tree[x].add; tree[x<<1].val%=mod; tree[x<<1|1].val%=mod; tree[x].add=0; } } void build(int i,int l,int r){ tree[i].l=l; tree[i].r=r; tree[i].add=0; if(l == r){ tree[i].val=wt[l]; tree[i].val%=mod; return; } int mid=(l+r)>>1; build(i<<1,l,mid); build(i<<1|1,mid+1,r); push_up(i); } void update(int i,int l,int r,int L,int R,int c){ if(l >= L && r <= R){ tree[i].val+=(r-l+1)*c; tree[i].add+=c; return; } push_down(i,r-l+1); int mid=(l+r)>>1; if(L <= mid)update(i<<1,l,mid,L,R,c); if(R > mid)update(i<<1|1,mid+1,r,L,R,c); push_up(i); } void query(int i,int l,int r,int L,int R){ if(l >= L && r <= R){ ans+=tree[i].val; ans%=mod; return; } push_down(i,r-l+1); int mid=(l+r)>>1; if(L <= mid)query(i<<1,l,mid,L,R); if(R > mid)query(i<<1|1,mid+1,r,L,R); } void dfs1(int x,int pre,int deep){///确定各节点层次,子树大小,父节点编号,重儿子编号 dep[x]=deep; fa[x]=pre; siz[x]=1; int maxson=-1; for(int i=head[x];i != -1;i=edge[i].next){ int v=edge[i].to; if(v != pre){ dfs1(v,x,deep+1); siz[x]+=siz[v]; if(siz[v] > maxson){maxson=siz[v];son[x]=v;} } } } void dfs2(int x,int topf){///确定各链的信息,包括链的顶点以及链上点的新编号 id[x]=++cnt; wt[id[x]]=w[x]; top[x]=topf; if(!son[x])return; dfs2(son[x],topf); for(int i=head[x];i != -1;i=edge[i].next){ int v=edge[i].to; if(v == fa[x] || v == son[x])continue; dfs2(v,v); } } void spilt(){ dfs1(rot,0,1); dfs2(rot,rot); build(1,1,n); } /*查询两点路径上的点权和*/ int qRange(int x,int y){///让深度深的点往上跳到顶点并更新对答案的贡献 int res=0; ///之后更新到旧链顶上的链,重复过程直到两点在同一条链上 while(top[x] != top[y]){ if(dep[top[x]] < dep[top[y]])swap(x,y); ans=0; query(1,1,n,id[top[x]],id[x]); res+=ans; res%=mod; x=fa[top[x]]; } if(dep[x] > dep[y])swap(x,y); ans=0; query(1,1,n,id[x],id[y]); res+=ans; return res%mod; } /*更新同查询*/ void updRange(int x,int y,int c){ c%=mod; while(top[x] != top[y]){ if(dep[top[x]] < dep[top[y]])swap(x,y); update(1,1,n,id[top[x]],id[x],c); x=fa[top[x]]; } if(dep[x] > dep[y])swap(x,y); update(1,1,n,id[x],id[y],c); } /*查询子树点权和*/ int qSon(int x){///由于新编号连续,直接查询树根到树根+树的大小,这段区间对应整个子树 ans=0; query(1,1,n,id[x],id[x]+siz[x]-1); return ans; } /*更新同查询*/ void updSon(int x,int c){ update(1,1,n,id[x],id[x]+siz[x]-1,c); } int main(){ memset(head,-1,sizeof head); n=read(),m=read(),rot=read(),mod=read(); for(int i=1;i<=n;i++)w[i]=read(); for(int i=1;i<=n-1;i++){ int a=read(),b=read(); addedge(a,b); addedge(b,a); } spilt();///剖分 for(int i=1;i<=m;i++){ int op,x,y,z; op=read(); if(op == 1){ x=read(),y=read(),z=read(); updRange(x,y,z); } if(op == 2){ x=read(),y=read(); printf("%d\n",qRange(x,y)); } if(op == 3){ x=read(),y=read(); updSon(x,y); } if(op == 4){ x=read(); printf("%d\n",qSon(x)); } } return 0; }
原文:https://www.cnblogs.com/DuskOB/p/9998579.html