ytree

题目

2023湖南省赛E

先不考虑-1的d次,维护的信息变换一下变成
= x + k(du - dv)
= x - k*dv + k * du

查询时是单点查询,想到dfn序建立两个树状数组分别维护 x - k*dv 和 k
-1的d次如何判断,可以发现只有当父亲和子节点的深度为一奇一偶时才有-1,其余都是1
那可以在添加时乘(-1)^父亲的深度,再查询时在乘(-1)^查询节点的深度即可

重置,就用set存下操作序列,二分找到符合条件的再删去,由于每个操作最多进set一次出set一次,复杂度不变

最开始读假,以为对包括它为子树的情况也要清除影响,如果这样只能用线段树的区间重重,懒标记增加一个清零,对于操作3强制清零其子树对应的dfn区间即可

#include<bits/stdc++.h>
using namespace std;
const int mod = 1e9 + 7;
const int N = 2e5 + 10;
int head[N], nx[N*2], to[N*2], dep[N], in[N], out[N];
int id = 1;
int dfn = 1;
const int inf = 1e9;
void ad(int x, int y) {
	to[id] = y;
	nx[id] = head[x];
	head[x] = id++;
}

void dfs(int cur, int fa) {
	dep[cur] = dep[fa] + 1;
	in[cur] = dfn++;
	for (int i = head[cur]; i > 0; i = nx[i]) {
		if (to[i] == fa) {
			continue;
		}
		dfs(to[i], cur);
	}
	out[cur] = dfn;
}

struct BIT {
	int n;
	vector<int> a;
	BIT(int _n) {
		n = _n;
		a.assign(n+1,0);
	}
	void update(int p, int v) {
		for (int i = p; i <= n; i += i & -i) {
			a[i] = (a[i] + v) % mod;
		}
	}
	
	void update(int l, int r, int v) {
		update(l,v);
		update(r+1, -v);
	}
	
	int query(int p) {
		int sum = 0;
		for (int i = p; i > 0; i -= i & -i) {
			sum = (sum + a[i]) % mod;
		}
		return sum;
	}
};

signed main() {
	ios::sync_with_stdio(0);
	cin.tie(0);
	int n, q;
	cin >> n >> q;
	for (int i = 2; i <= n; i++) {
		int x;
		cin >> x;
		ad(i,x);
		ad(x,i);
	}
	
	dep[0] = 0;
	dfs(1,0);
	
	// (x + k * d)
	// x + k * (du - dv)
	// x + k * du - k * dv
	// x - k * dv + k * du
	//  用两个树状数组维护 两个信息
	// 有没有 -1 分别用再添加和查询时*深度决定

	BIT tree1(n+1), tree2(n+1);
	struct node {
		int v, x, k;
		bool operator< (const node& b) const {
			if (in[v] == in[b.v]) {
				return x < b.x;
			} else {
				return in[v] < in[b.v];
			}
		}
	};
	set<node> st;
	
	while (q--) {
		int op, v, x, k;
		cin >> op;
		if (op == 1) {
			cin >> v >> x >> k;	
			st.insert({v,x,k});
			tree1.update(in[v], out[v] - 1, (x - k * dep[v]) * (dep[v]%2 ? -1 : 1));
			tree2.update(in[v], out[v] - 1, k * (dep[v]%2 ? -1 : 1));
		} else if (op == 2) {
			cin >> v;
			int res = tree1.query(in[v]) + tree2.query(in[v]) * (dep[v]);
			res = (res*(dep[v]%2 ? -1: 1) + mod) % mod;
			cout << res << '\n';
		} else if (op == 3) {
			cin >> v;
			while (true) {
				auto fd = st.lower_bound({v,-inf,-inf});
				if (fd == st.end() || in[(*fd).v] >= out[v]) {
					break;
				}
				int tv = (*fd).v;
				int tx = -(*fd).x, tk = -(*fd).k;
				tree1.update(in[tv], out[tv] - 1, (tx - tk * dep[tv]) * (dep[tv]%2 ? -1 : 1));
				tree2.update(in[tv], out[tv] - 1, tk * (dep[tv]%2 ? -1 : 1));
				st.erase(fd);
			}
		}
	}
	return 0;
}
github