gjh303987897 @ 2023-04-04 09:48:51
#include<iostream>
#include<algorithm>
#include<cmath>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<vector>
#include<map>
#include<stack>
#include<stdlib.h>
#include<queue>
#include<climits>
int read(){
int x=0,f=1; char ch=getchar();
while(ch>'9'||ch<'0'){ if(ch=='-'){ f=-1; } ch=getchar(); }
while(ch>='0'&&ch<='9'){ x=(x<<3)+(x<<1)+(ch^48); ch=getchar(); }
return x*f;
}
int n,m,r,p;
const int maxn = 1e5+11;
int w[maxn];
struct tree{
int next;
int to;
}t[maxn<<1];
int head[maxn<<1],js;
void add(int u,int v){
t[++js].next=head[u];
t[js].to=v;
head[u]=js;
}
int fa[maxn];
int dep[maxn];
int subtree_size[maxn];
int son[maxn];
void dfs1(int now,int father,int deep){
fa[now]=father;
dep[now]=deep;
subtree_size[now]=1;
int maxx = -1;
for(int i=head[now];i;i=t[i].next){
int y = t[i].to;
if(y==father) continue;
dfs1(y,now,deep+1);
subtree_size[now]+=subtree_size[y];
if(subtree_size[y]>maxx){
maxx=subtree_size[y];
son[now]=y;
}
}
}
int cnt;
int tree_w[maxn];
int node_id[maxn];
int top[maxn];
void dfs2(int now,int topf){
node_id[now]=++cnt;
tree_w[cnt]=w[now];
top[now]=topf;
if(!son[now]) return;
dfs2(son[now],topf);
for(int i=head[now];i;i=t[i].next){
int y = t[i].to;
if(y==son[now]||y==fa[now]) continue;
dfs2(y,y);
}
}
int seg_tree[maxn<<2];
int lazy_tag[maxn<<2];
int tree_l[maxn],tree_r[maxn];
void pushdown(int now,int l,int r){
lazy_tag[now<<1]+=lazy_tag[now];
lazy_tag[now<<1|1]+=lazy_tag[now];
seg_tree[now<<1]+=lazy_tag[now]*(tree_r[now<<1]-tree_l[now<<1]+1);
seg_tree[now<<1|1]+=lazy_tag[now]*(tree_r[now<<1|1]-tree_l[now<<1|1]+1);
seg_tree[now<<1]%=p;
seg_tree[now<<1|1]%=p;
lazy_tag[now]=0;
}
void build(int now,int l,int r){
if(l==r){
seg_tree[now]=tree_w[l]%p;
tree_l[now]=tree_r[now]=r;
lazy_tag[now]=0;
return;
}
int mid = (l+r)>>1;
build(now<<1,l,mid);
build(now<<1|1,mid+1,r);
seg_tree[now]=seg_tree[now<<1|1]+seg_tree[now<<1];
seg_tree[now]%=p;
tree_l[now]=tree_l[now<<1];
tree_r[now]=tree_r[now<<1|1];
}
int quary(int now,int l,int r,int q_l,int q_r){
int ans = 0;
if(l>=q_l&&r<=q_r){
ans+=seg_tree[now];
ans%=p;
return ans;
}
int mid = (l+r)>>1;
if(lazy_tag[now]) pushdown(now,tree_l[now],tree_r[now]);
if(q_l<=mid) ans+=quary(now<<1,l,mid,q_l,q_r)%p;
if(q_r>mid) ans+=quary(now<<1|1,mid+1,r,q_l,q_r)%p;
return ans%p;
}
void update(int now,int l,int r,int q_l,int q_r,int num){
if(l>=q_l&&l<=q_r){
lazy_tag[now]+=num;
seg_tree[now]+=(r-l+1)*num;
seg_tree[now]%=p;
return;
}
int mid = (l+r)>>1;
if(lazy_tag[now]) pushdown(now,tree_l[now],tree_r[now]);
if(q_l<=mid) update(now<<1,l,mid,q_l,q_r,num);
if(q_r>mid) update(now<<1|1,mid+1,r,q_l,q_r,num);
seg_tree[now]=seg_tree[now<<1]+seg_tree[now<<1|1];
seg_tree[now]%=p;
}
void q_update(int x,int y,int z){
z%=p;
while (top[x]!=top[y]){
if(dep[top[x]]<dep[top[y]]) std:: swap(x,y);
update(1,1,n,node_id[top[x]],node_id[x],z);
x=fa[top[x]];
}
if(dep[x]<dep[y]) std:: swap(x,y);
update(1,1,n,node_id[y],node_id[x],z);
}
int q_quary(int x,int y){
int ans=0;
while(top[x]!=top[y]){
if(dep[top[x]]<dep[top[y]]) std:: swap(x,y);
ans+=quary(1,1,n,node_id[top[x]],node_id[x])%p;
x=fa[top[x]];
}
if(dep[x]<dep[y]) std:: swap(x,y);
ans+=quary(1,1,n,node_id[y],node_id[x])%p;
return ans;
}
void q_update_subtree(int x,int z){
z%=p;
update(1,1,n,node_id[x],node_id[x]+subtree_size[x]-1,z);
}
int q_quary_subtree(int x){
return quary(1,1,n,node_id[x],node_id[x]+subtree_size[x]-1)%p;
}
int main(){
n=read(),m=read(),r=read(),p=read();
for(int i=1;i<=n;i++){
w[i]=read();
}
for(int i=1;i<=n-1;i++){
int x=read(),y=read();
add(x,y);
add(y,x);
}
dfs1(r,0,1);
dfs2(r,r);
build(1,1,n);
for(int i=1;i<=m;i++){
int judge=read();
if(judge==1){
int x=read(),y=read(),z=read();
q_update(x,y,z);
}
if(judge==2){
int x=read(),y=read();
std:: cout<<q_quary(x,y)<<std:: endl;
}
if(judge==3){
int x=read(),z=read();
q_update_subtree(x,z);
}
if(judge==4){
int x=read();
std:: cout<<q_quary_subtree(x)<<std:: endl;
}
}
return 0;
}