rt,只能过两个点
刚学oi要自闭了
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define f(q,w,e) for(register int q=w;q<=e;++q)
#define ff(q,w,e) for(register int q=w;q>=e;--q)
#define mid ((l+r)>>1)
#define ls (k<<1)
#define rs ((k<<1)|1)
#define xs double
#define lb(x) x&(-x)
const int N=4*1e5+5;
const int mod=571373;
inline ll w(){char c=getchar();ll ret=0,fs=1; while(c<'0'||c>'9'){if(c=='-') fs=-1;c=getchar();} while(c>='0'&&c<='9'){ret=(ret<<1)+(ret<<3)+c-'0';c=getchar();}return ret*fs;}
int n,T,p,root;
vector<int>e[N];
//==================线段树================================
int t[N],//线段树主体
tag[N],//加法标记
a[N];//按时间戳处理后的点权
int ww[N];//原输入点权
void build(int k,int l,int r){
tag[k]=0;
if(l==r){
t[k]=a[l]%p;
return;
}
build(ls,l,mid);
build(rs,mid+1,r);
t[k]=(t[ls]+t[rs])%p;
}
void pushdown(int k,int l,int r){
if(!tag[k]) return;
tag[ls]=(tag[ls]+tag[k])%p;
tag[rs]=(tag[rs]+tag[k])%p;
t[ls]=(t[ls]+tag[ls]*(mid-l+1))%p;
t[rs]=(t[rs]+tag[k]*(r-mid))%p;
tag[k]=0;
}
void modify(int k,int l,int r,int x,int y,int v){
if(x<=l&&r<=y){
tag[k]=(tag[k]+v)%p;
t[k]=(t[k]+(r-l+1)*v)%p;
return;
}
pushdown(k,l,r);
if(x<=mid) modify(ls,l,mid,x,y,v);
if(y>mid) modify(rs,mid+1,r,x,y,v);
t[k]=(t[ls]+t[rs])%p;
}
int query(int k,int l,int r,int x,int y){
if(l>y||x>r) return 0;
if(x<=l&&r<=y){
return t[k];
}
pushdown(k,l,r);
int res=0;
if(x<=mid) res=(res+query(ls,l,mid,x,y))%p;
if(y>mid) res=(res+query(rs,mid+1,r,x,y))%p;
return res;
}
//=====================x线段树================================
int fa[N],//
sz[N],//子树大小
hs[N],//重儿子
dep[N];//深度
void dfs1(int x,int ff,int depp){
fa[x]=ff;dep[x]=depp;sz[x]=1;
int maxs=-1;
ff(i,e[x].size()-1,0){
int to=e[x][i];
if(to==ff) continue;
dfs1(to,x,depp+1);
sz[x]+=sz[to];
if(sz[to]>maxs){
hs[x]=to;maxs=sz[to];
}
}
}
int top[N],//重链顶端
dfn[N],//时间戳
tim=0;
void dfs2(int x,int Top){
dfn[x]=++tim;top[x]=Top;
a[tim]=ww[x];
if(!hs[x]) return;
dfs2(hs[x],Top);
ff(i,e[x].size()-1,0){
int to=e[x][i];
if(to==fa[x]||to==hs[x]) continue;
dfs2(to,to);
}
}
void range_modify(int x,int y,int z){
z%=p;
while(top[x]!=top[y]){
if(dep[top[x]]<dep[top[y]]) swap(x,y);
modify(1,1,n,dfn[top[x]],dfn[x],z);
x=fa[top[x]];
}
if(dep[x]>dep[y]) swap(x,y);
modify(1,1,n,dfn[x],dfn[y],z);
}
int range_query(int x,int y){
int res=0;
while(top[x]!=top[y]){
if(dep[top[x]]<dep[top[y]]) swap(x,y);
res=(res+query(1,1,n,dfn[top[x]],dfn[x]))%p;
x=fa[top[x]];
}
if(dep[x]>dep[y]) swap(x,y);
return (res+query(1,1,n,dfn[x],dfn[y]))%p;
}
void subtree_modify(int x,int z){
z%=p;
modify(1,1,n,dfn[x],dfn[x]+sz[x]-1,z);
}
int subtree_query(int x){
return query(1,1,n,dfn[x],dfn[x]+sz[x]-1);
}
//======================================================
int main(){
n=w(),T=w(),root=w(),p=w();
f(i,1,n){//输入点权
ww[i]=w();
}
f(i,1,n-1){//输入边
int x=w(),y=w();
e[x].push_back(y);
e[y].push_back(x);
}
dfs1(root,0,1);
dfs2(root,root);
build(1,1,n);
while(T--){//输入操作
int op=w();
if(op==1){//两点修改
int x=w(),y=w(),z=w();
range_modify(x,y,z);
}
if(op==2){//两点查询
int x=w(),y=w();
printf("%d\n",range_query(x,y));
}
if(op==3){//子树修改
int x=w(),z=w();
subtree_modify(x,z);
}
if(op==4){//子树查询
int x=w();
printf("%d\n",subtree_query(x));
}
}
}