模板题链接:https://www.luogu.com.cn/problem/P3384
这个树剖的知识点不难,只要理解了什么是重链,怎么把一棵树重新编号,让它满足建成一颗线段树的线性条件,那么就很容易了,我打了两边,第一遍那个查询区域和修改区域的地方错了,第二次也是这块区域出了点小问题,还有线段树更新里面最后那里忘记重新计算和了。。
下面是我第一次打的模板,嗯~整体结构一般吧。。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 200010;
inline ll read(){
ll x = 0,f = 1; char ch = getchar();
while(ch < '0' || ch > '9') {if(ch == '-') f = -1; ch = getchar();}
while(ch >= '0' && ch <= '9') {x = (x<<3) + (x<<1) + (ch ^ '0'); ch = getchar();}
return x * f;
}
/*-----------------------------------以上预处理-----------------------------------*/
struct edge{ //链式向前星
int to,next;
}edges[maxn];
int head[maxn],cnt1; // 链式向前星用到的变量
void add_edge(int u,int v){
edges[++cnt1].next = head[u];
edges[cnt1].to = v;
head[u] = cnt1;
}
int top[maxn],fa[maxn],dep[maxn],son[maxn],siz[maxn],id[maxn],cnt2; //每条链的顶点,父节点,深度,重儿子,还有dfs2新编号的id,用到的编号变量
ll w[maxn],wt[maxn]; //原序号权值,新编号的权值
int N,M,R,mod; //节点数,边数,根,模
struct Node{
int l,r;
ll add,sum;
}nodes[maxn<<1];
/*-----------------------------------以上数据定义-----------------------------------*/
void build(int l,int r,int p){
nodes[p].l = l, nodes[p].r = r;
if(l == r){
nodes[p].sum = wt[l] % mod;
return;
}
int mid = (l+r) >> 1;
build(l,mid,p<<1);
build(mid+1,r,p<<1|1);
nodes[p].sum = (nodes[p<<1].sum + nodes[p<<1|1].sum) % mod;
}
void push_down(int p){
nodes[p<<1].add = (nodes[p<<1].add + nodes[p].add) % mod;
nodes[p<<1|1].add = (nodes[p<<1|1].add + nodes[p].add) % mod;
nodes[p<<1].sum = (nodes[p<<1].sum + nodes[p].add * (nodes[p<<1].r - nodes[p<<1].l + 1)) % mod;
nodes[p<<1|1].sum = (nodes[p<<1|1].sum + nodes[p].add * (nodes[p<<1|1].r - nodes[p<<1|1].l + 1)) % mod;
nodes[p].add = 0;
}
void add(int l,int r,ll k,int p){
if(l <= nodes[p].l && nodes[p].r <= r){
nodes[p].sum = (nodes[p].sum + k * (nodes[p].r - nodes[p].l + 1)) % mod;
nodes[p].add = (nodes[p].add + k);
return;
}
if(nodes[p].add) push_down(p);
int mid = (nodes[p].l + nodes[p].r) >> 1;
if(l <= mid) add(l,r,k,p<<1);
if(r > mid) add(l,r,k,p<<1|1);
nodes[p].sum = (nodes[p<<1].sum + nodes[p<<1|1].sum) % mod;
}
ll query(int l,int r,int p){
if(l <= nodes[p].l && nodes[p].r <= r){
return nodes[p].sum;
}
push_down(p);
ll ans = 0;
int mid = (nodes[p].l + nodes[p].r) >> 1;
if(l <= mid) ans += query(l,r,p<<1);
if(r > mid) ans += query(l,r,p<<1|1);
return ans % mod;
}
/*-----------------------------------以上线段树-----------------------------------*/
void dfs1(int x,int f, int deep){
dep[x] = deep;
fa[x] = f;
siz[x] = 1;
int maxson = -1;
for(int i = head[x]; i; i = edges[i].next){
int to = edges[i].to;
if(to == f) continue;
dfs1(to,x,deep+1);
siz[x] += siz[to];
if(maxson < siz[to]){maxson = siz[to]; son[x] = to;}
}
}
void dfs2(int x,int topf){
id[x] = ++cnt2;
wt[cnt2] = w[x];
top[x] = topf;
if(!son[x]) return;
dfs2(son[x],topf);
for(int i = head[x]; i; i = edges[i].next){
int to = edges[i].to;
if(to == fa[x] || to == son[x]) continue;
dfs2(to,to);
}
}
ll query_range(int x,int y){
ll ans = 0;
while(top[x] != top[y]){
if(dep[top[x]] < dep[top[y]]) swap(x,y);
ans = (ans + query(id[top[x]],id[x],1)) % mod;
x = fa[top[x]];
}
if(dep[x] > dep[y]) swap(x,y);
ans = (ans + query(id[x],id[y],1))%mod;
return ans;
}
void add_range(int x,int y,ll k){
while(top[x] != top[y]){
if(dep[top[x]] < dep[top[y]]) swap(x,y);
add(id[top[x]],id[x],k,1);
x = fa[top[x]];
}
if(dep[x] > dep[y]) swap(x,y);
add(id[x], id[y],k, 1);
}
ll query_son(int x){
return query(id[x],id[x] + siz[x] - 1,1);
}
void add_son(int x,int k){
add(id[x],id[x] + siz[x] - 1,k,1);
}
int main(){
N = read(),M = read(),R = read(),mod = read();
for(int i = 1;i<=N;i++){
w[i] = read();
}
int u,v;
for(int i = 1;i<N;i++){
u = read(),v = read();
add_edge(u,v);
add_edge(v,u);
}
dfs1(R,0,1);
dfs2(R,R);
build(1,N,1);
int op,x,y;
ll z;
for(int i = 1; i<=M; i++){
op = read();
if(op == 1){
x = read(),y = read(),z = read();
add_range(x,y,z);
}
else if(op == 2){
x = read(), y = read();
printf("%lld\n",query_range(x,y));
}
else if(op == 3){
x = read(), z = read();
add_son(x,z);
}else{
x = read();
printf("%lld\n",query_son(x));
}
}
// system("pause");
return 0;
}