Dec. 30th 2025

今年最后一次竞赛课

DFS 序4


思路很简单

将一条链的信息存储至一个点上

信息设计

  • 节点信息:

    不存储

  • tag 信息:

    1. (只改节点的) tag1
    2. (改子树的):
      • tag2\(\to\) ans += (depth[x] + 1) * tree[id].tag2
      • tag3\(\to\) ans -= tree[id].tag3

封闭性:显然(若只存储后面两个则会丢失单点权值修改的信息)

代码 没有调

#include<bits/stdc++.h>
using namespace std;

using lf = double;
using ll = long long;
using ull = unsigned long long;
using pii = pair<ll, int>;

int read() {
	int k = 0, f = 1;
	char c = getchar();
	while (c < '0' || c > '9') {
		if (c == '-')f = -1;
		c = getchar();
	}
	while (c >= '0' && c <= '9')k = k * 10 + c - '0', c = getchar();
	return k * f;
}
void print(ll x) {
	if (x < 0)putchar('-'), x = -x;
	if (x < 10)putchar(x + '0');
	else print(x / 10), putchar(x % 10 + '0');
}

const int maxn = 1e6 + 5;
ll ls(ll i) {return i << 1;}
ll rs(ll i) {return i << 1 | 1;}

int n, m, root, id;
ll a[maxn];
//ll tree[maxn << 2], tag1[maxn << 2], tag2[maxn << 2], tag3[maxn << 2];
ll depth[maxn];
ll in[maxn], out[maxn], dfs[maxn]; // dfn + out + dfs
bool vis[maxn];
vector<int> adj[maxn];
int v[maxn];

struct sgt{
	int t1, t2, t3;
	int sum; // useless
} tree[maxn << 2];

void maintain(int id) { // push up
	tree[id].sum = ~~(0 + 0);
}

void build(int id, int left, int right) {
	if (left == right) {
//		tree[id] = v[dfs[left]];
		return;
	}
	ll mid = (left + right) >> 1;
	build(ls(id), left, mid);
	build(rs(id), mid + 1, right);
	maintain(id);
}

void addtag(ll d, int id, int left, int right) {
	return tree[id].t1 += d, void();
}

void addtag2(ll d, int id, int left, int right) {
	return tree[id].t2 += d, void();
}

void addtag3(ll d, int id, int left, int right) {
	return tree[id].t3 += d * depth[dfs[id]], void();
}

void pushdown(int id, int left, int right, int d = 0) {
	if (tree[id].t1) {
		ll mid = (left + right) >> 1;
		addtag(tree[id].t1, ls(id), left, mid);
		addtag(tree[id].t1, rs(id), mid + 1, right);
		tree[id].t1 = 0;
	}
	if (tree[id].t2) {
		ll mid = (left + right) >> 1;
		addtag2(tree[id].t2, ls(id), left, mid);
		addtag2(tree[id].t2, rs(id), mid + 1, right);
		tree[id].t2 = 0;
	}
	if (tree[id].t3) {
		ll mid = (left + right) >> 1;
		addtag3(tree[id].t3, ls(id), left, mid);
		addtag3(tree[id].t3, rs(id), mid + 1, right);
		tree[id].t3 = 0;
	}
}

void update_p(int L, int R, ll d, int id = 1, int left = 1, int right = n) {
	if (L <= left && right <= R) {
		addtag(d, id, left, right);
		return;
	}
	pushdown(id, left, right);
	ll mid = (left + right) >> 1;
	if (L <= mid) update_p(L, R, d, ls(id), left, mid);
	if (R > mid) update_p(L, R, d, rs(id), mid + 1, right);
	maintain(id);
}

void update_r(int L, int R, ll d, int id = 1, int left = 1, int right = n) {
	if (L <= left && right <= R) {
		addtag2(d, id, left, right);
		return;
	}
	pushdown(id, left, right);
	ll mid = (left + right) >> 1;
	if (L <= mid) update_r(L, R, d, ls(id), left, mid);
	if (R > mid) update_r(L, R, d, rs(id), mid + 1, right);
	maintain(id);
}

sgt query(ll posi, int id = 1, int left = 1, int right = n) { // point query
	if (left == right)
		return tree[id];
	pushdown(id, left, right);
	ll mid = (left + right) >> 1;
	if (posi <= mid) return query(posi, ls(id), left, mid);
	else return query(posi, rs(id), mid + 1, right);
}

void DFS(int u) { // init
	in[u] = ++id;
	dfs[id] = u;
	vis[u] = true;
	for (int v : adj[u])
		if (!vis[v]) {
			depth[v] = depth[u] + 1;
			DFS(v);
		}
	out[u] = id;
}

struct node{ // lca queries
	int p, id;
	node() = default;
	node(int __, int ___) : p(__), id(___) {}
};

bool visited[maxn];
int fa[maxn], lca[maxn];
vector<node> qry[maxn];

int find(int x) { // dij set
	if (fa[x] == x) return x;
	return fa[x] = find(fa[x]);
}

void tarjan(int u) { // lca
	visited[u] = true;
	for (int v : adj[u]) 
		if (!vis[v]) {
			tarjan(v);
			fa[v] = u;
		}
	
	for (node q : qry[u]) {
		int x = q.p, id = q.id;
		if (visited[x])
			lca[id] = find(x);
	}
}

struct qr{ // save the queries
	int opt;
	int a, b, x;
	qr() = default;
	qr(int o, int __, int ___) {
		if (o == 3) {
			opt = o;
			a = __;
			b = ___;
		} else {
			opt = o;
			a = __;
			x = ___;
		}
	}
} queries[maxn];

void solve() {
	
	n = read();
	m = read();
	root = read();
	
	for (int i = 1; i <= n; i++) cin >> v[i];
	for (int i = 1; i < n; i++) {
		int u = read(), v = read();
		adj[u].push_back(v);
		adj[v].push_back(u);
	}
	
//	build(1, 1, n);
	
	for (int i = 1; i <= m; i++) {
		int opt = read(), a = read(), b = read();
		queries[i] = {opt, a, b};
		if (opt == 3) {
			qry[a].emplace_back(b, i);
			qry[b].emplace_back(a, i);
		}
	}
	
	//	vis[root] = 1;
	DFS(root);
	tarjan(root);
	
	for (int i = 1; i <= n; i++) // init
		update_p(in[i], out[i], v[i]);
	
	for (int i = 1; i <= m; i++) {
		int o = queries[i].opt;
		if (o == 3) { // chain query
			int a = queries[i].a, b = queries[i].b;
			int lca_node = lca[i];
			
			sgt _ = query(in[a]), __ = query(in[b]), ___ = query(in[lca_node]);
			
			ll ansa = _.t1 + _.t2 * (depth[dfs[a]] + 1) - _.t3;
			ll ansb = __.t2 + __.t2 * (depth[dfs[b]] + 1) - __.t3;
			ll ans_lca = ___.t1 + ___.t2 * (depth[dfs[lca_node]] + 1) - ___.t3;
			
			cout << ansa + ansb - ans_lca << "\n";
		} else { // other : update node a or subtree of node a
			int a = queries[i].a, x = queries[i].x;
			
			if (o == 1) update_p(in[a], out[a], x);
			else if (o == 2) update_r(in[a], out[a], x);
		}
	}
	
}

int main() {
	
//	freopen("T1.in", "r", stdin);
//	freopen("T1.out", "w", stdout);
	
	int T = 1;
	while (T--) solve();
	
	return 0;
}
posted @ 2025-12-30 21:31  Yangyihao  阅读(2)  评论(0)    收藏  举报