模板——树链剖分
放个板子而已。。
#include<stdio.h>
#include<algorithm>
#define ls root<<1
#define rs root<<1|1
using namespace std;
typedef long long ll;
int n,m,r;ll res,p;
const int MAXN = 100005;
ll a[MAXN];
struct edge{
int v,nxt;
}e[MAXN<<1];
struct TREE{
int lazy,l,r,val;
}tree[MAXN*4];
int head[MAXN];int cnt=0;int dep[MAXN];int fa[MAXN];int son[MAXN];int size[MAXN];int top[MAXN];int newval[MAXN];int id[MAXN];
int tot=0;
inline void add(int u,int v){
e[++cnt].v = v;e[cnt].nxt = head[u];head[u] = cnt;
}
inline void pushdown(int root,int len){
tree[ls].lazy += tree[root].lazy;
tree[rs].lazy += tree[root].lazy;
tree[ls].val += tree[root].lazy * (len-(len>>1));
tree[rs].val += tree[root].lazy * (len>>1);
tree[ls].val %= p;
tree[rs].val %= p;
tree[root].lazy = 0;
}
inline void update(int root,int L,int R,int l,int r,ll k){
if(l <= L && R <= r){
tree[root].lazy += k;
tree[root].val += (R-L+1)*k;
}
else{
int mid = (L + R) >> 1;
if(tree[root].lazy) pushdown(root,R-L+1);
if(l <= mid) update(ls,L,mid,l,r,k);
if(r >= mid+1) update(rs,mid+1,R,l,r,k);
tree[root].val = tree[ls].val + tree[rs].val;
tree[root].val %= p;
}
}
inline void query(int root,int L,int R,int l,int r){
if(l <= L && R <= r){
res += tree[root].val;
res %= p;
return ;
}
else{
int mid = (L + R) >> 1;
if(tree[root].lazy) pushdown(root,R-L+1);
if(l <= mid) query(ls,L,mid,l,r);
if(r >= mid+1) query(rs,mid+1,R,l,r);
}
}
//////////////////////////线段树分割线////////////////////////////////////
inline void dfs1(int root,int father,int depth){
dep[root] = depth;
fa[root] = father;
size[root] = 1;
for(int i=head[root];i;i=e[i].nxt){
int v = e[i].v;
if(v == father) continue;
dfs1(v,root,depth+1);
size[root] += size[v];
if(!son[root] || size[v] > size[son[root]]){
son[root] = v;
}
}
}
inline void dfs2(int u,int nowtop){
id[u] = ++tot;
top[u] = nowtop;
newval[tot] = a[u];
if(!son[u]) return ;
dfs2(son[u] , nowtop);
for(int i=head[u];i;i=e[i].nxt){
int v = e[i].v;
if(v == fa[u] || v == son[u]) continue;
dfs2(v,v);
}
}
inline void build(int root,int l,int r){
if(l == r){
tree[root].val = newval[l];
tree[root].val %= p;
return ;
}
int mid = (l + r) >> 1;
build(ls,l,mid);
build(rs,mid+1,r);
tree[root].val = tree[ls].val + tree[rs].val;
tree[root].val %= p;
}
inline void addrange(int l,int r,ll num){
while(top[l] ^ top[r]){
if(dep[top[l]] < dep[top[r]]) swap(l,r);
update(1,1,n,id[top[l]],id[l],num);
l = fa[top[l]];
}
if(dep[l] > dep[r]) swap(l,r);
update(1,1,n,id[l],id[r],num);
}
inline int queryrange(int l,int r){
int ans = 0;
while(top[l] ^ top[r]){
if(dep[top[l]] < dep[top[r]]) swap(l,r);
res=0;
query(1,1,n,id[top[l]],id[l]);
ans += res;
ans %= p;
l = fa[top[l]];
}
if(dep[l] > dep[r]) swap(l,r);
res=0;
query(1,1,n,id[l],id[r]);
ans += res;
return ans%p;
}
int main(){
scanf("%d%d%d%lld",&n,&m,&r,&p);
for(int i=1;i<=n;++i) scanf("%lld",&a[i]);
for(int i=1;i<n;++i){
int u,v;scanf("%d%d",&u,&v);
add(u,v);add(v,u);
}
dfs1(r,0,1);
dfs2(r,r);
build(1,1,n);
for(;m;--m){
int k;scanf("%d",&k);
switch (k){
case 1:{
int x,y;ll z;
scanf("%d%d%lld",&x,&y,&z);
z %= p;
addrange(x,y,z);
break;
}
case 2:{
int x,y;
scanf("%d%d",&x,&y);
printf("%d\n",queryrange(x,y));
break;
}
case 3:{
int x;ll z;
scanf("%d%lld",&x,&z);
update(1,1,n,id[x],id[x]+size[x]-1,z);
break;
}
case 4:{
int x;scanf("%d",&x);
res = 0;
query(1,1,n,id[x],id[x]+size[x]-1);
printf("%lld\n",res%p);
break;
}
}
}
return 0;
}