题目:树链剖分
#include <bits/stdc++.h>
using namespace std;
const int Max=100005;
int n,m,s,tot,root,mod;
int l[Max],r[Max],father[Max],first[Max],num[Max],depth[Max];
int top[Max],rev[Max],seg[Max],size[Max],son[Max];
int tree[Max<<2],add[Max<<2];
struct shu{int to,next;};
shu edge[Max<<1];
inline int get_int()
{
int x=0,f=1;
char c;
for(c=getchar();(!isdigit(c))&&(c!='-');c=getchar());
if(c=='-') f=-1,c=getchar();
for(;isdigit(c);c=getchar()) x=(x<<3)+(x<<1)+c-'0';
return x*f;
}
inline void print(int x)
{
if(x>9) print(x/10);
putchar('0'+x%10);
}
inline void build(int x,int y)
{
edge[++s].next=first[x];
first[x]=s;
edge[s].to=y;
}
inline void dfs1(int p){
size[p]=1;
for(int i=first[p];i;i=edge[i].next){
int v=edge[i].to;
if(v==father[p])continue;
father[v]=p,depth[v]=depth[p]+1,dfs1(v),size[p]+=size[v];
if(size[v]>size[son[p]])son[p]=v;
}
}
inline void dfs2(int p,int tp){
top[p]=tp,seg[rev[p]=++tot]=p;
if(!son[p])return;
dfs2(son[p],tp);
for(int i=first[p];i;i=edge[i].next){
int v=edge[i].to;
if(v!=son[p]&&v!=father[p])dfs2(v,v);
}
}
inline void pushdown(int root,int l,int r,int mid)
{
if(!add[root]) return;
tree[root<<1]=(tree[root<<1]+add[root]*(mid-l+1))%mod;
tree[root<<1|1]=(tree[root<<1|1]+add[root]*(r-mid))%mod;
add[root<<1]=(add[root<<1]+add[root])%mod;
add[root<<1|1]=(add[root<<1|1]+add[root])%mod;
add[root]=0;
}
inline void update(int root){tree[root]=(tree[root<<1]+tree[root<<1|1])%mod;}
inline void buildtree(int root,int l,int r)
{
if(l==r) {tree[root]=num[seg[l]];return;}
int mid=(l+r)>>1;
buildtree(root<<1,l,mid),buildtree(root<<1|1,mid+1,r);
update(root);
}
inline void change(int root,int l,int r,int L,int R,int num)
{
if(L<=l&&R>=r){tree[root]+=(r-l+1)*num,add[root]+=num;return;}
int mid=(l+r)>>1;
pushdown(root,l,r,mid);
if(L<=mid) change(root<<1,l,mid,L,R,num);
if(R>mid) change(root<<1|1,mid+1,r,L,R,num);
update(root);
}
inline int Q(int root,int l,int r,int L,int R)
{
if(L<=l&&R>=r) return tree[root];
int mid=(l+r)>>1,sum=0;
pushdown(root,l,r,mid);
if(L<=mid) sum=(sum+Q(root<<1,l,mid,L,R))%mod;
if(R>mid) sum=(sum+Q(root<<1|1,mid+1,r,L,R))%mod;
return sum;
}
inline void modify(int x,int y,int z)
{
// if(!y) {change(1,1,tot,l[x],r[x],z);return;}
while(top[x]!=top[y])
{
if(depth[top[x]]<depth[top[y]]) swap(x,y);
change(1,1,tot,rev[top[x]],rev[x],z);
x=father[top[x]];
}
if(depth[x]>depth[y]) swap(x,y);
change(1,1,tot,rev[x],rev[y],z);
}
inline int ask(int x,int y)
{
int ans=0;
while(top[x]!=top[y])
{
if(depth[top[x]]<depth[top[y]]) swap(x,y);
ans=(ans+Q(1,1,tot,rev[top[x]],rev[x]))%mod;
x=father[top[x]];
}
if(depth[x]>depth[y]) swap(x,y);
ans=(ans+Q(1,1,tot,rev[x],rev[y]))%mod;
return ans;
}
int main()
{
n=get_int(),m=get_int(),root=get_int(),mod=get_int();
for(int i=1;i<=n;i++) num[i]=get_int();
for(int i=1;i<n;i++)
{
int x=get_int(),y=get_int();
build(x,y),build(y,x);
}
dfs1(root),dfs2(root,root);
buildtree(1,1,tot);
for(int i=1;i<=m;i++)
{
int tag=get_int(),x=get_int(),y,z;
switch(tag)
{
case 1:
y=get_int(),z=get_int(),modify(x,y,z);
break;
case 2:
y=get_int(),print(ask(x,y)),putchar('\n');
break;
case 3:
z=get_int(),change(1,1,tot,rev[x],rev[x]+size[x]-1,z);
break;
case 4:
print(Q(1,1,tot,rev[x],rev[x]+size[x]-1)),putchar('\n');
break;
}
}
return 0;
}