这里是来凑个帖的,勿看。
#include <bits/stdc++.h>
using namespace std;
const int N = 100010 ;
#define int long long
struct edge{
int to,next ;
}e[N<<1];
int head[N],f[N],dep[N],size[N],son[N],rk[N],top[N],dfn[N];
int a[N];
//f[i]:i的父亲,dep[i]:i的深度,size[i]:i的子树大小,son[i]:重儿子 ,rk[i]:i的dfs值,与dfn相反
//top[i]:i所在链的顶端,dfn[i]:dfs序,时间戳
int n,m,rt,tot,cnt;
int p,r ;
inline void add(int x,int y){
e[++cnt].to=y;
e[cnt].next=head[x] ;
head[x]=cnt ;
}
void dfs1(int rt,int fa,int depth){ //主要处理深度,父亲和儿子
f[rt]=fa;dep[rt]=depth;size[rt]=1;//一些初始化
for (int i=head[rt];i;i=e[i].next){
int to=e[i].to ;
if (to==fa) continue ;//保证不是父亲
dfs1(to,rt,depth+1) ;
size[rt]+=size[to] ;//rt的大小+子树的大小
if (size[son[rt]]<size[to]) son[rt]=to ;//改变重儿子
}
return ;
}
void dfs2(int rt,int t){ //主要处理链,dfs序
top[rt]=t;dfn[rt]=++cnt;rk[cnt]=rt;//初始化
if (!son[rt]) return ;//该点没有重儿子
dfs2(son[rt],t) ;//rt的重儿子也是和rt一样处于以t为顶端的重链
for (int i=head[rt];i;i=e[i].next){
int to=e[i].to ;
if (to!=f[rt] && to!=son[rt]) dfs2(to,to) ;//一个点位于轻链底端,那么它的top必然是它本身
}
return ;
}
struct seg{ //线段树
int ls,rs,lazy,l,r;
int sum ;
}tree[N<<1];
inline void pushup(int rt){
tree[rt].sum=(tree[tree[rt].ls].sum+tree[tree[rt].rs].sum+
tree[rt].lazy*(tree[rt].r-tree[rt].l+1))%p;
return ;
}
void build(int ll,int rr,int rt){ //create
if (ll==rr){
tree[rt].l=tree[rt].r=ll ;
tree[rt].sum=a[rk[ll]] ;
return ;
}
else {
int mid=(ll+rr)>>1;
tree[rt].ls=cnt++ ;
tree[rt].rs=cnt++ ;
build(ll,mid,tree[rt].ls) ;
build(mid+1,rr,tree[rt].rs) ;
tree[rt].l=tree[tree[rt].ls].l ;
tree[rt].r=tree[tree[rt].rs].r ;
pushup(rt) ;
}
return ;
}
void update(int l,int r,int rt,int c){ //l~r +c
if (l<=tree[rt].l && tree[rt].r<=r) {
tree[rt].sum=(tree[rt].sum+c*(tree[rt].r-tree[rt].l+1))%p ;
tree[rt].lazy=(tree[rt].lazy+c)%p ;
}
else {
int mid=(tree[rt].l+tree[rt].r)>>1 ;
if (l<=mid) update(l,r,tree[rt].ls,c) ;
if (mid<r) update(l,r,tree[rt].rs,c) ;
pushup(rt) ;
}
return ;
}
int query(int l,int r,int rt){
if (l<=tree[rt].l && tree[rt].r<=r) return tree[rt].sum ;
int tot=(tree[rt].lazy*(min(r,tree[rt].r)-max(l,tree[rt].l)+1)%p)%p ;//初始值
int mid=(tree[rt].l+tree[rt].r)>>1 ;
if (l<=mid) tot=(tot+query(l,r,tree[rt].ls))%p ;
if (mid<r) tot=(tot+query(l,r,tree[rt].rs))%p ;
return tot%p ;
}
inline int sum(int x,int y){
int ans=0;
int fx=top[x],fy=top[y] ;
while (fx!=fy){
if (dep[fx]>=dep[fy]) {
ans=(ans+query(dfn[fx],dfn[x],rt))%p ;
x=f[fx],fx=top[x] ;
}
else {
ans=(ans+query(dfn[fy],dfn[y],rt))%p ;
y=f[fy],fy=top[y] ;
}
}
if (dfn[x]<=dfn[y]) ans=(ans+query(dfn[x],dfn[y],rt))%p ;
else ans=(ans+query(dfn[y],dfn[x],rt))%p ;
return ans%p ;
}
inline void UPDATE(int x,int y,int c){
int fx=top[x],fy=top[y];
while(fx!=fy)
{
if(dep[fx]>=dep[fy]){
update(dfn[fx],dfn[x],rt,c) ;
x=f[fx],fx=top[x];
}
else {
update(dfn[fy],dfn[y],rt,c) ;
y=f[fy],fy=top[y];
}
}
if (dfn[x]<=dfn[y]) update(dfn[x],dfn[y],rt,c) ;
else update(dfn[y],dfn[x],rt,c) ;
return ;
}
main(){
scanf("%lld%lld%lld%lld",&n,&m,&r,&p) ;
for (int i=1;i<=n;i++) scanf("%lld",&a[i]) ;
for (int i=1;i<n;i++){
int x,y ;
scanf("%lld%lld",&x,&y) ;
add(x,y);
add(y,x) ;
}
cnt=0 ;
dfs1(r,0,1) ;
dfs2(r,r) ;
cnt=0;
rt=cnt++ ;
build(1,n,rt);
for (int i=1;i<=m;i++){
int x,y,op ;
int z ;
scanf("%lld",&op);
if (op==1){
scanf("%lld%lld%lld",&x,&y,&z) ;
UPDATE(x,y,z) ;
}
else if (op==2){
scanf("%lld%lld",&x,&y) ;
printf("%lld\n",sum(x,y)) ;
}
else if (op==3){
scanf("%lld%lld",&x,&z) ;
update(dfn[x],dfn[x]+size[x]-1,rt,z) ;
}
else{
scanf("%lld",&x) ;
printf("%lld\n",query(dfn[x],dfn[x]+size[x]-1,rt)) ;
}
}
}