版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/kidsummer/article/details/82144263
一个代码模板。
#include <bits/stdc++.h>
#define mem(x,v) memset(x,v,sizeof(x))
#define go(i,a,b) for (int i = a; i <= b; i++)
#define og(i,a,b) for (int i = a; i >= b; i--)
#define MID(a,b) (a + b) / 2
#define lson now << 1
#define rson now << 1 | 1
using namespace std;
typedef long long LL;
const double EPS = 1e-10;
const int INF = 0x3f3f3f3f;
const int N = 1e5+100;
int n,m,r,p; //正常读入。
int lazy[N<<2],val[N<<2]; //线段树。
int cnt = -1,Head[N],Next[N],to[N],w[N],wt[N];//权值,邻接表
int son[N],id[N],f[N],tim,size[N],top[N],dep[N];//树剖数组。
// 重儿子,入队时间戳,父亲节点,子树大小,链的顶端,深度。
int res = 0;
void Add_edge(int u, int v){
to[++cnt] = v;
Next[cnt] = Head[u];
Head[u] = cnt;
}
void dfs1(int u, int fa, int deep){ //解决深度,子树大小,重儿子,父亲节点。
dep[u] = deep; //deep
f[u] = fa; size[u] = 1;// father , size of node.
for (int i = Head[u]; i != -1; i = Next[i]){
int v = to[i];
if (v == fa) continue;
dfs1(v,u,deep+1);
size[u] += size[v]; //size of u.
if (size[v] > size[son[u]]) son[u] = v; // 找u 的重儿子。
}
}
void dfs2(int u, int topf){
id[u] = ++tim; //时间戳
wt[tim] = w[u];//权值
top[u] = topf; //找链顶。
if (!son[u]) return;
dfs2(son[u],topf); //先找重儿子,
for (int i = Head[u]; i != -1; i = Next[i]){ //再找轻儿子。
int v = to[i];
if (v == f[u] || v == son[u]) continue; //如果是重儿子,或者父亲节点,跳过。
dfs2(v,v);
}
}
// 线段树操作
void push_down(int now, int len){
if (lazy[now] == 0) return;
val[lson] = (val[lson] + lazy[now]*(len >> 1)) % p;
val[rson] = (val[rson] + lazy[now]*(len - (len >> 1))) % p;
lazy[lson] = (lazy[lson] + lazy[now]);
lazy[rson] = (lazy[rson] + lazy[now]);
lazy[now] = 0;
}
void Build(int now, int a, int b){
if (a + 1 == b){
val[now] = wt[a] % p;
return;
}
int m = MID(a,b);
Build(lson,a,m); Build(rson,m,b);
val[now] = (val[lson] + val[rson]) % p;
}
int Query(int now, int a, int b, int l, int r){
int ans = 0;
if (l <= a && r >= b - 1){
return (val[now] % p);
}
int m = MID(a,b);
push_down(now,b-a);
if (l < m) ans = (ans + Query(lson,a,m,l,r))%p;
if (r >= m) ans = (ans + Query(rson,m,b,l,r)) % p;
return ans;
}
void Insert(int now, int a, int b, int l, int r, int k){
if (l <= a && r >= b - 1){
val[now] = (val[now] + k * (b - a))%p;
lazy[now] += k;
return;
}
push_down(now,b-a);
int m = MID(a,b);
if (l < m) Insert(lson,a,m,l,r,k);
if (r >= m) Insert(rson,m,b,l,r,k);
val[now] = (val[lson] + val[rson]) % p;
}
// 线段树操作
int qRange(int x, int y){
int ans = 0;
while(top[x] != top[y]){
if (dep[top[x]] < dep[top[y]]) swap(x,y); // 把 x 变成深度大的点。
ans = (ans + Query(1,1,n+1,id[top[x]],id[x])) % p;//处理路径上的和。
x = f[top[x]]; //到达链顶的父亲节点,就是换一条链。
}
if (dep[x] < dep[y]) swap(x,y);//在同一条链,不一定相等。把x 变成深度大的点。
ans = (ans + Query(1,1,1+n,id[y],id[x])) % p; //处理路径上的和。
return ans;
}
void upRange(int x, int y, int k){ //同上。
k %= p;
while(top[x] != top[y]){
if (dep[top[x]] < dep[top[y]]) swap(x,y);
Insert(1,1,n+1,id[top[x]],id[x],k);
x = f[top[x]];
}
if (dep[x] < dep[y]) swap(x,y);
Insert(1,1,n+1,id[y],id[x],k);
}
int qSon(int x){
return Query(1,1,n+1,id[x],id[x]+size[x]-1);
}
void upSon(int x, int k){
Insert(1,1,n+1,id[x],id[x] + size[x] -1,k);
}
int main(){
scanf("%d%d%d%d",&n,&m,&r,&p);
go(i,1,n) scanf("%d",&w[i]);
mem(Head,-1);
go(i,2,n){
int x,y;
scanf("%d%d",&x,&y);
Add_edge(x,y); Add_edge(y,x);
}
dfs1(r,0,1);
dfs2(r,r);
Build(1,1,n+1);
while(m--){
int op,x,y,z;
scanf("%d",&op);
if (op == 1){
scanf("%d%d%d",&x,&y,&z);
upRange(x,y,z);
} else
if (op == 2) {
scanf("%d%d",&x,&y);
printf("%d\n",qRange(x,y));
} else
if (op == 3){
scanf("%d%d",&x,&y);
upSon(x,y);
} else {
scanf("%d",&x);
printf("%d\n",qSon(x));
}
}
return 0;
}