dfs序线段树求调
查看原帖
dfs序线段树求调
481337
FwbAway楼主2025/6/26 17:49
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N = 110000;
int n, m;
int a[N];
int cnt;
int in[N], out[N];
int sum[N << 1];
pair<int, int> ops[N << 1];
vector<int> e[N];
struct node {
	int l, r;
	int lz;
	int sum;
} tree[N << 3];//本来是2*n,四倍空间是 8*n 
void push_up(int u) {
	tree[u].sum = tree[u << 1].sum + tree[u << 1 | 1].sum;//上传 
}
void push_down(int u) {
	if (tree[u].lz) {//下传懒惰标记 
		tree[u << 1].sum += (sum[tree[u << 1].r] - sum[tree[u << 1].l - 1]) * tree[u].lz;
		tree[u << 1 | 1].sum += (sum[tree[u << 1 | 1].r] - sum[tree[u << 1 | 1].l - 1]) * tree[u].lz;
		tree[u << 1].lz += tree[u].lz;
		tree[u << 1 | 1].lz += tree[u].lz;
		tree[u].lz = 0;
	}
}
void dfs(int u, int fa) {
	in[u] = ++cnt;//在2*n的序列中u的入队位置在cnt 
	ops[cnt] = make_pair(u, 1);//当前位置的节点为u,入队为1 
	for (int v : e[u]) {
		if (v != fa) {
			dfs(v, u);
		}
	}
	out[u] = ++cnt;//在序列中u的出队位置在cnt 
	ops[cnt] = make_pair(u, -1);//当前位置的节点为u,出队为-1 
}
void build(int u, int l, int r) {
	tree[u].l = l, tree[u].r = r;//左右子树 
	if (l == r) {
		tree[u].sum = ops[l].second * a[ops[l].first];//当前节点的值 
		return ;
	}
	int mid = l + r >> 1;
	build(u << 1, l, mid);
	build(u << 1 | 1, mid + 1, r);
	push_up(u);
}
void add(int u, int id, int k) {
	if (tree[u].l == tree[u].r) {//已经找到了 
		tree[u].sum += k;
		return ;
	}
	push_down(u);//下传 
	if (id <= tree[u << 1].r) add(u << 1, id, k);
	else add(u << 1 | 1, id, k);
	push_up(u);
}
void update(int u, int l, int r, int k) {
	if (l <= tree[u].l && tree[u].r <= r) {//在范围内 
		tree[u].lz += k;//懒惰标记 
		tree[u].sum += (sum[tree[u].r] - sum[tree[u].l - 1]) * k;//当前节点个数*节点增加数目k 
		return ;
	}
	push_down(u);//下传 
	if (l <= tree[u << 1].r) update(u << 1, l, r, k);
	if (r >= tree[u << 1 | 1].l) update(u << 1 | 1, l, r, k);
	push_up(u);
}
int query(int u, int l, int r) {
	if (tree[u].l <= l && tree[u].r <= r) {
		return tree[u].sum;//找到区间范围 
	}
	push_down(u);//下传 
	int s = 0;
	if (l <= tree[u << 1].r) s += query(u << 1, l, r);
	if (r >= tree[u << 1 | 1].l) s += query(u << 1 | 1, l, r);
	return s;
}
signed main() {
	scanf("%lld%lld", &n, &m);
	for (int i = 1; i <= n; i++) {
		scanf("%lld", &a[i]);
	}
	for (int i = 1; i < n; i++) {
		int u, v;
		scanf("%lld%lld", &u, &v);
		e[u].push_back(v);
		e[v].push_back(u);
	}
	dfs(1, -1);
	for (int i = 1; i <= (n << 1); i++) {
		sum[i] = sum[i - 1] + ops[i].second;//在2*n的序列中计算进出队列的前缀和来计算区间内的点个数 
	}
	build(1, 1, n << 1);//线段树建树 
	while (m--) {
		int op;
		scanf("%lld", &op);
		if (op == 1) {
			int x, y;
			scanf("%lld%lld", &x, &y);
			add(1, in[x], y);//将x入队的节点值+y 
			add(1, out[x], -y);//将x出队的节点值-y 
		} else if (op == 2) {
			int x, y;
			scanf("%lld%lld", &x, &y);
			update(1, in[x], out[x], y);//将x的子树[in[x],out[x]]全部+y 
		} else {
			int x;
			scanf("%lld", &x);
			printf("%lld\n", query(1, 1, in[x]));
		}
	}
	return 0;
}

WA&RE 0pts.

2025/6/26 17:49
加载中...