class版树链剖(刨)分
感谢沙华大佬的赞助
其实没什么太大变化,就是用了几次一顿乱指。。。
CODE:
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#define ls (rt<<1)
#define rs (rt<<1|1)
#define mid ((l+r)>>1)
#define pushup(rt) t[rt].data=(t[ls].data+t[rs].data)%mod
#define N 100005
using namespace std;
int n,m,mod,tot,res;
int top[N],cnt,w[N],wt[N],head[N];
int fa[N],deep[N],idx[N],son[N],size[N];
class subdivision {
private:
struct edge {
int next,to;
}e[(N<<1)];
private:
struct segtree {
int data,left,right,tag;
inline int len() { return right - left + 1; }
}t[(N<<2)];
public:
inline void edge_build(int u,int v) {
e[++tot].to = v;
e[tot].next = head[u];
head[u] = tot;
return ;
}
public:
inline void tree_build(int rt , int l , int r){
t[rt].left = l;
t[rt].right = r;
t[rt].tag = 0;
if(l == r) {
t[rt].data = wt[l];
return ;
}
tree_build(ls,l,mid);
tree_build(rs,mid +1,r);
pushup(rt);
return ;
}
private:
inline void pushdown(int rt) {
t[ls].tag = (t[ls].tag + t[rt].tag) % mod;
t[rs].tag = (t[rs].tag + t[rt].tag) % mod;
t[ls].data = (t[ls].data + t[rt].tag * t[ls].len() ) % mod;
t[rs].data = (t[rs].data + t[rt].tag * t[rs].len() ) % mod;
t[rt].tag = 0;
return ;
}
public:
inline void update(int rt , int ll , int rr , int w) {
int l = t[rt].left;
int r = t[rt].right;
if(ll <= l && r <= rr) {
t[rt].tag += w;
t[rt].data = (t[rt].data + t[rt].len() * w) % mod;
return ;
}
if(t[rt].tag) pushdown(rt);
if(ll <= mid) update(ls,ll,rr,w);
if(rr > mid) update(rs,ll,rr,w);
pushup(rt);
return ;
}
public:
inline void query(int rt,int ll,int rr) {
int l = t[rt].left;
int r = t[rt].right;
if(ll <= l && r <= rr) {
res += t[rt].data;
return ;
}
if(t[rt].tag) pushdown(rt);
if(ll <= mid) query(ls,ll,rr);
if(rr > mid) query(rs,ll,rr);
return ;
}
public:
inline void dfs1(int now,int f,int dep) {
deep[now] = dep;
fa[now] = f;
size[now] = 1;
int maxson = -1;
for(int i = head[now] ; i ; i = e[i].next) {
int y = e[i].to;
if(y == f) continue;
dfs1(y , now , dep + 1);
size[now] += size[y];
if(size[y] > maxson) {
son[now] = y;
maxson = size[y];
}
}
return ;
}
public:
inline void dfs2(int now,int topf) {
idx[now] = ++cnt;
wt[cnt] = w[now];
top[now] = topf;
if(!son[now]) return ;
dfs2(son[now],topf);
for(int i = head[now] ; i ; i = e[i].next) {
int y = e[i].to;
if(y == fa[now] || y == son[now]) continue;
dfs2(y,y);
}
return ;
}
public:
inline int qrange(int x,int y) {
int ans = 0;
while(top[x] != top[y]) {
if(deep[top[x]] < deep[top[y]]) swap(x,y);
res = 0;
query(1 , idx[top[x]] , idx[x]);
ans = (ans + res) % mod;
x = fa[top[x]];
}
if(deep[x] > deep[y]) swap(x,y);
res = 0;
query(1 , idx[x] , idx[y]);
return (ans + res) % mod;
}
public:
inline void uprange(int x,int y,int k) {
k %= mod;
while(top[x] != top[y]) {
if(deep[top[x]] < deep[top[y]]) swap(x,y);
update(1 , idx[top[x]] , idx[x],k);
x = fa[top[x]];
}
if(deep[x] > deep[y]) swap(x,y);
update(1 , idx[x] , idx[y] , k);
return ;
}
};
subdivision *s;
int main(){
int root,a,b;
scanf("%d%d%d%d",&n,&m,&root,&mod);
for(int i = 1 ; i <= n ; ++i)
scanf("%d",&w[i]);
for(int i = 1 ; i < n ; ++i){
scanf("%d%d",&a,&b);
s->edge_build(a,b);
s->edge_build(b,a);
}
s->dfs1(root,0,1);
s->dfs2(root,root);
s->tree_build(1,1,n);
int k,x,y,z;
while(m--) {
scanf("%d%d",&k,&x);
if(k == 1) {
scanf("%d%d",&y,&z);
s->uprange(x,y,z);
}
if(k == 2) {
scanf("%d",&y);
printf("%d
",s->qrange(x,y) );
}
if(k == 3) {
scanf("%d",&z);
s->update(1 , idx[x] , idx[x] + size[x]-1,z);
}
if(k == 4) {
res = 0;
s->query(1 , idx[x] , idx[x] + size[x]-1);
printf("%d
",res % mod);
}
}
return 0;
}