https://www.luogu.com.cn/problem/P3384
#include<bits/stdc++.h>
using namespace std;
const int maxn = 5e5+10;
#define lson num<<1
#define rson num<<1|1
#define mid ((l+r)>>1)
struct node
{
int to,next;
} edge[maxn<<1];
int head[maxn<<1],cnt,mod,ans,n;
int fa[maxn],depth[maxn],Size[maxn],son[maxn],top[maxn],id[maxn],rk[maxn],arr[maxn],w[maxn],lazi[maxn];
template<typename T> inline void read(T &x)
{
x=0;
T w=1,ch=getchar();
while(!isdigit(ch)&&ch!='-')ch=getchar();
if(ch=='-')w=-1,ch=getchar();
while(isdigit(ch))x=(x<<3)+(x<<1)+(ch^'0'),ch=getchar();
x=x*w;
}
void down(int num,int len)
{
lazi[lson] +=lazi[num];
lazi[rson]+=lazi[num];
arr[lson]+=lazi[num]*(len-(len>>1));
arr[rson]+=lazi[num]*(len>>1);
arr[lson]%=mod;
arr[rson]%=mod;
lazi[num] = 0;
}
void build(int l, int r, int num)
{
if(l==r)
{
arr[num] = rk[l];
arr[num]%=mod;
return;
}
build(l,mid,lson);
build(mid+1,r,rson);
arr[num] = arr[lson]+arr[rson];
arr[num]%=mod;
}
void sum(int l,int r,int num,int left, int right)
{
if(left<=l&&r<=right)
{
ans +=arr[num];
ans%=mod;
return;
}
if(lazi[num])
down(num,r-l+1);
if(left<=mid)
sum(l,mid,lson,left,right);
if(right>mid)
sum(mid+1,r,rson,left,right);
}
void add(int l,int r,int num,int left,int right,int increase)
{
if(left<=l&&right>=r)
{
lazi[num]+=increase;
arr[num]+=increase*(r-l+1);
return;
}
if(lazi[num])
down(num,r-l+1);
if(left<=mid)
add(l,mid,lson,left,right,increase);
if(right>mid)
add(mid+1,r,rson,left,right,increase);
arr[num] = (arr[lson]+arr[rson])%mod;
}
void add_edge(int u,int v)
{
edge[cnt].to = v;
edge[cnt].next = head[u];
head[u] = cnt++;
}
void dfs1(int x,int father,int deep)//处理出父亲和深度和子树大小
{
fa[x] = father;
depth[x] = deep;
Size[x] = 1;
for(int i = head[x]; i !=-1; i = edge[i].next)
{
int to = edge[i].to;
if(to == father)
continue;
dfs1(to,x,deep+1);
Size[x]+=Size[to];
if(Size[to]>Size[son[x]])
son[x] = to;
}
}
void dfs2(int x, int t)//连接重链,标记dfs序,处理出top,rk,id
{
top[x] = t;
id[x] = ++cnt;
rk[cnt] = w[x];
if(!son[x])
return;
dfs2(son[x],t);
for(int i = head[x]; i != -1; i = edge[i].next)
{
int to = edge[i].to;
if(to!=fa[x]&&to!=son[x])
dfs2(to,to);
}
}
int min_road(int x,int y)//求两点之间最短路径权值
{
int anss=0;
while(top[x]!=top[y])
{
if(depth[top[x]]<depth[top[y]])
swap(x,y);
ans = 0;
sum(1,n,1,id[top[x]],id[x]);
anss += ans;
anss%=mod;
x=fa[top[x]];
}
if(depth[x]>depth[y])
swap(x,y);
ans = 0;
sum(1,n,1,id[x],id[y]);
anss +=ans;
anss %=mod;
return anss;
}
int sum_son(int x)
{
ans = 0;
sum(1,n,1,id[x],id[x]+Size[x]-1);//子树区间右端点为id[x]+siz[x]-1
return ans;
}
void add_road(int x,int y,int k)//x到y最短路径加上k
{
k%=mod;
while(top[x]!=top[y])
{
if(depth[top[x]]<depth[top[y]])
swap(x,y);
add(1,n,1,id[top[x]],id[x],k);
x=fa[top[x]];
}
if(depth[x]>depth[y])
swap(x,y);
add(1,n,1,id[x],id[y],k);
}
void add_son(int x,int k)
{
add(1,n,1,id[x],id[x]+Size[x]-1,k);
}
int main()
{
int i,m,r,a,b,c,ope;
read(n);
read(m);
read(r);
read(mod);
memset(head,-1,sizeof(head));
cnt = 0;
for(i = 1; i<=n; i++)
{
read(w[i]);
}
for(i = 0; i <n-1; i++)
{
read(a);
read(b);
add_edge(a,b);
add_edge(b,a);
}
cnt = 0;
dfs1(r,0,1);
dfs2(r,r);
build(1,n,1);
while(m--)
{
read(ope);
if(ope ==1)
{
read(a);
read(b);
read(c);
add_road(a,b,c);
}
else if(ope == 2)
{
read(a);
read(b);
printf("%d\n",min_road(a,b));
}
else if(ope == 3)
{
read(a);
read(b);
add_son(a,b);
}
else if(ope ==4)
{
read(a);
printf("%d\n",sum_son(a));
}
}
return 0;
}