蒟蒻 T on #11球调
查看原帖
蒟蒻 T on #11球调
763215
foglake楼主2025/8/30 10:28

思路大概是一种奇奇怪怪的树剖?

向子树大的那边延伸链,设链头为 h,对于操作 C,将 x 到 h 全打上一遍标记,对于操作 Q,若 h 的标记数减 x 标记数大于 1 则路径上有标记,直接暴搜,否则直接跳到 f[h] 继续判断

#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e5 + 10;
int siz[maxn], f[maxn], bel[maxn], mar[maxn], vis[maxn], lest;
vector <int> e[maxn], h;
int get_size(int x, int fr) {
	f[x] = fr, siz[x] = 1;
	for (auto i : e[x]) if (i != fr) siz[x] += get_size(i, x);
	return siz[x];
}
void build_list(int x, int fr, int p, int len) {
	if (p == -1) h.push_back(x), p = x;
	bel[x] = h.size() - 1;
	int nex = 0; for (auto i : e[x]) if (i != fr && siz[i] >= siz[nex]) nex = i;
	if (len < lest) build_list(nex, x, p, len + 1); else nex = 0; //令链长不超过 logn, 以提升效率
	for (auto i : e[x]) if (i != fr && i != nex) build_list(i, x, -1, 1);
}
int query(int x) {
	if (vis[h[bel[x]]] > vis[x] || mar[x]) {
		while (!mar[x]) x = f[x];
		return x;
	}
	return query(f[h[bel[x]]]);
}
int main() {
	int n, q; scanf("%d%d", &n, &q);
	lest = ceil(log2(n));
	for (int i = 1; i < n; i++) {
		int u, v; scanf("%d%d", &u, &v);
		e[u].push_back(v), e[v].push_back(u);
	}
	get_size(1, -1), build_list(1, -1, -1, 1);
	mar[1] = vis[1] = 1;
	for (int i = 1; i <= q; i++) {
		char p; int x; scanf(" %c%d", &p, &x);
		if (p == 'C') {
			int rot = x; mar[x] = 1;
			while (rot != f[h[bel[x]]]) vis[rot] ++, rot = f[rot];
		} else printf("%d\n", query(x));
	}
}
2025/8/30 10:28
加载中...