題目鏈接:https://www.luogu.org/problemnew/show/P3384
思路:樹鏈剖分模板題,至於線段樹,寫這個的應該都會線段樹纔對emmm。
#pragma GCC optimize(2)
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <bitset>
#include <cmath>
#include <cctype>
#include <iostream>
#include <algorithm>
#include <string>
#include <vector>
#include <queue>
#include <map>
#include <set>
#include <sstream>
#include <iomanip>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const ll inff = 0x3f3f3f3f3f3f3f3f;
#define FOR(i,a,b) for(int i(a);i<=(b);++i)
#define FOL(i,a,b) for(int i(a);i>=(b);--i)
#define REW(a,b) memset(a,b,sizeof(a))
#define inf int(0x3f3f3f3f)
#define si(a) scanf("%d",&a)
#define sl(a) scanf("%lld",&a)
#define sd(a) scanf("%lf",&a)
#define ss(a) scanf("%s",a)
#define mod ll(998244353)
#define pb push_back
#define eps 1e-12
#define lc d<<1
#define rc d<<1|1
#define Pll pair<ll,ll>
#define P pair<int,int>
#define pi acos(-1)
ll n,m,r,p,a[200008],tot,x,y,fa[200008],son[200008],sz[200008],head[200008],deep[200008],id[200008],b[200008],cnt,top[200008],z,op;
struct as{
ll l,r,su,lz;
}tr[200007<<2];
struct node{
int next,to;}e[300008];
void add1(int a,int b)
{
e[tot].next=head[a];
e[tot].to=b;
head[a]=tot++;
}
void push(int d){tr[d].su=(tr[lc].su+tr[rc].su)%p;}
void build(int d,int l,int r)
{
tr[d].l=l,tr[d].r=r,tr[d].lz=0;
if(l==r) {tr[d].su=b[l]%p;return;}
int mid=(l+r)>>1;
build(lc,l,mid);
build(rc,mid+1,r);
push(d);
}
void pushh(int d)
{
if(tr[d].lz==0) return;
tr[lc].lz=(tr[lc].lz+tr[d].lz)%p,tr[rc].lz=(tr[rc].lz+tr[d].lz)%p;
tr[lc].su=(tr[lc].su+tr[d].lz*(tr[lc].r-tr[lc].l+1))%p;
tr[rc].su=(tr[rc].su+tr[d].lz*(tr[rc].r-tr[rc].l+1))%p;
tr[d].lz=0;
}
void add(int d,int l,int r,ll pos)
{
if(tr[d].l==l&&tr[d].r==r)
{
tr[d].lz=(tr[d].lz+pos)%p;
tr[d].su=(tr[d].su+pos*(r-l+1))%p;
return;
}
pushh(d);
int mid=(tr[d].l+tr[d].r)>>1;
if(mid>=r) add(lc,l,r,pos);
else if(l>mid) add(rc,l,r,pos);
else add(lc,l,mid,pos),add(rc,mid+1,r,pos);
push(d);
}
ll query(int d,int l,int r)
{
if(tr[d].l==l&&tr[d].r==r) {return tr[d].su;}
pushh(d);
int mid=(tr[d].l+tr[d].r)>>1;
if(mid>=r) return query(lc,l,r);
else if(l>mid) return query(rc,l,r);
else return (query(lc,l,mid)+query(rc,mid+1,r));
push(d);
}
void dfs(int u,int f,int de)
{
sz[u]=1,fa[u]=f,deep[u]=de;
int maxson=0;
for(int i=head[u];i!=-1;i=e[i].next)
{
int v=e[i].to;
if(v==f) continue;
dfs(v,u,de+1);
sz[u]+=sz[v];
if(sz[v]>maxson) son[u]=v,maxson=sz[v];
}
}
void dfs1(int u,int tfa)
{
id[u]=++cnt,b[cnt]=a[u],top[u]=tfa;
if(!son[u]) return;
dfs1(son[u],tfa);
for(int i=head[u];i!=-1;i=e[i].next)
{
int v=e[i].to;
if(v==fa[u]||v==son[u]) continue;
dfs1(v,v);
}
}
ll Query(int l,int r)
{
ll ans=0;
while(top[l]!=top[r])
{
if(deep[top[l]]<deep[top[r]]) swap(l,r);
ans+=query(1,id[top[l]],id[l]);
l=fa[top[l]];
}
if(deep[l]<deep[r]) swap(l,r);
ans+=query(1,id[r],id[l]);
return (ans%p);
}
void Add(int l,int r,ll z)
{
while(top[l]!=top[r])
{
if(deep[top[l]]<deep[top[r]]) swap(l,r);
add(1,id[top[l]],id[l],z);
l=fa[top[l]];
}
if(deep[l]<deep[r]) swap(l,r);
add(1,id[r],id[l],z);
}
int main()
{
cin.tie(0);
cout.tie(0);
REW(head,-1);
cin>>n>>m>>r>>p;
FOR(i,1,n) sl(a[i]);
FOR(i,1,n-1) sl(x),sl(y),add1(x,y),add1(y,x);
dfs(r,0,1),dfs1(r,r);
build(1,1,n);
while(m--)
{
sl(op);
if(op==1) sl(x),sl(y),sl(z),z%=p,Add(x,y,z);
else if(op==3) sl(x),sl(z),z%=p,add(1,id[x],id[x]+sz[x]-1,z);
else if(op==2) sl(x),sl(y),cout<<(Query(x,y)%p)<<endl;
else if(op==4) sl(x),cout<<(query(1,id[x],id[x]+sz[x]-1)%p)<<endl;
}
return 0;
}