#include<bits/stdc++.h> using namespace std ; const int MAXN = 100010; int a[MAXN],dt[MAXN],n,m,r,p,cnt; int dep[MAXN],fa[MAXN],son[MAXN],siz[MAXN],topc[MAXN],ID[MAXN],res; struct Edge{ int to,nxt; }edge[MAXN];//tree's Edge -> MAXN-1 int head[MAXN],ectr; void addedge(int from,int to){ ectr++; edge[ectr].to = to; edge[ectr].nxt = head[from]; head[from] = ectr; } struct Tree{ int l ,r ,dat ,lazy ; }tree[MAXN<<2]; void build(int q,int l,int r){ tree[q].l=l,tree[q].r=r; if(l == r){ tree[q].dat = dt[l]; if(tree[q].dat > p) tree[q].dat%=p; return ; } int mid = (l+r)/2; build(q<<1,l,mid); build(q<<1|1,mid+1,r); tree[q].dat = tree[q<<1].dat + tree[q<<1|1].dat; return ; } void change (int q, int l, int r, int d)//?????? { if(tree[q].l==l && tree[q].r==r) { tree[q].dat+=d*(r-l+1); tree[q].lazy+=d; return ; } int mid = ( tree[q].l + tree[q].r ) /2;//?????? if(tree[q].lazy!=0) { change ( q<<1, tree[q].l, mid, tree[q].lazy); change ( q<<1|1, mid+1, tree[q].r, tree[q].lazy); tree[q].lazy=0; } if(r<=mid) change ( q*2, l, r, d); else if(l>mid) change( q*2+1, l, r, d); else { change ( q*2, l, mid, d) ; change ( q*2+1, mid+1, r, d) ; } tree[q].dat = tree[q*2].dat + tree[q*2+1].dat; return; } int query(int q, int l, int r) { int mid = ( tree[q].l + tree[q].r ) / 2; if(tree[q].l==l && tree[q].r==r) return tree[q].dat; if(tree[q].lazy!=0) { change ( q<<1, tree[q].l, mid, tree[q].lazy); change ( q<<1|1, mid+1, tree[q].r, tree[q].lazy); tree[q].lazy=0; } if(r<=mid) return query(q<<1, l, r); else if(l>mid) return query(q<<1|1, l, r); else return ( query(q<<1, l, mid) + query(q<<1|1, mid+1, r) ); } void BRONYA_IS_THE_BEST(int x,int y,int deep){//x -> now , y -> father siz[x] = 1; dep[x] = deep; fa[x] = y; int maxson = -1; for(register int i = head[x];i;i = edge[i].nxt){ int v = edge[i].to; if (v==y) continue; BRONYA_IS_THE_BEST(v,x,deep+1); siz[x] += siz[v]; if(siz[v] > maxson) { son[x] = v; maxson = siz[v]; } } return ; } void TERISHA_IS_THE_CUTEST(int x ,int ct){//ct == chain_top ID[x] = ++cnt ; dt[cnt] = a[x]; topc[x] = ct; if(!son[x]) return ; TERISHA_IS_THE_CUTEST(son[x],ct); for(register int i = head[x];i ;i = edge[i].nxt){ int v = edge[i].to; if(v == fa[x] || v == son[x]) continue ; TERISHA_IS_THE_CUTEST(v,v); } return ; } int I_WANT_YAYI_S_XX(int x,int y){//?????????? int ans = 0; while (topc[x] != topc[y]){//??topc???????????????ID[] if(dep[x] < dep[y]) swap(x,y);//?????????? res = query(1,ID[topc[x]],ID[x]); ans += res; ans %= p; x = fa[topc[x]];//???? } if(dep[x] > dep[y]) swap(x,y); res = query(1,ID[x],ID[y]); ans+=res; ans%=p; return ans ;//? } int CSY_IS_PSYCHO(int x){ res = query(1,ID[x],ID[x]+siz[x]-1); return res ; } int main(){ scanf("%d%d%d%d",&n,&m,&r,&p);//r -> root ,p -> mod for(register int i=1;i<=n;i++){ scanf("%d",&a[i]); } for(register int i=1,x,y;i<n;i++){ scanf("%d%d",&x,&y); addedge(x,y); addedge(y,x); } BRONYA_IS_THE_BEST(r,0,1);//fa[r] = 0 TERISHA_IS_THE_CUTEST(r,r); for(register int i=1,flag;i<=m;i++){ scanf("%d",&flag); if(flag == 1){ int tra1,tra2,tra3; scanf("%d%d%d",&tra1,&tra2,&tra3); change(1,ID[tra1],ID[tra2],tra3); } if(flag == 2){ int tra1,tra2; scanf("%d%d",&tra1,&tra2); printf("%d",I_WANT_YAYI_S_XX(tra1,tra2)); } if(flag == 3){ int tra1,tra2; scanf("%d%d",&tra1,&tra2); change(1,ID[tra1],ID[tra1]+siz[tra1]-1,tra2); } if(flag == 4){ int tra1; scanf("%d",&tra1); printf("%d",CSY_IS_PSYCHO(tra1)); } } // for(int i=1;i<=n;i++){ // cout<<"NODE "<<i<<": siz="<<siz[i]<<",father="<<fa[i]<<",deep="<<dep[i]<<",bigson="<<son[i]<<endl; // } // for(int i=1;i<=n;i++){ // cout<<"NODE"<<i<<": newID="<<ID[i]<<",data="<<dt[ID[i]]<<endl;//NOTICE : dt[ID[i]] // } return 0; }