P4116 Qtree3 题解
前置知识:分块思想、树剖。
我有一个不用 set、不用数据结构的唐方法。
题解
先把树的重链剖出来。
充分发扬人类智慧,在树剖时如果当前重链长度
然后就可以暴力做了。
具体的,修改操作暴力的从当前节点
查询操作我们就一直往上不断跳链到根,不断更新最靠近根的链,最后在这条链上暴力跳找答案。
注意事项、坑点
不可以只维护一条链上有没有黑点,可以自己简单证一下。
代码
时间复杂度大概是
:::info[代码]
namespace SPT {
int fa[MAXN], dep[MAXN], sz[MAXN];
int son[MAXN], top[MAXN], button[MAXN];
void dfs1 (int u, int f) {
fa[u] = f;
dep[u] = dep[f] + 1;
sz[u] = 1;
for (auto v : g[u]) {
if (v == f) continue;
dfs1 (v, u);
sz[u] += sz[v];
if (sz[v] > sz[son[u]]) {
son[u] = v;
}
}
}
void dfs2 (int u, int tp, int len) {
top[u] = tp, button[tp] = u;
if (son[u]) {
if (len == blk) {
dfs2 (son[u], son[u], 1);
} else {
dfs2 (son[u], tp, len + 1);
}
}
for (auto v : g[u]) {
if (v != son[u] && v != fa[u]) {
dfs2 (v, v, 1);
}
}
}
} using namespace SPT;
void U (int x) {
int sgn = (col[x] ? -1 : 1);
for (int cur = button[top[x]]; cur != fa[x]; cur = fa[cur])
cnt[cur] += sgn;
col[x] ^= 1;
}
int Q (int x) {
int T = -1, ret = -1;
for (int cur = x; cur; cur = fa[top[cur]]) {
if (cnt[cur]) {
T = cur;
}
}
if (T == -1) {
return -1;
}
for (int cur = T; cur != fa[top[T]]; cur = fa[cur]) {
if (col[cur]) {
ret = cur;
}
}
return ret;
}
signed main () {
ios::sync_with_stdio (0);
cin.tie (0);
cin >> n >> q;
blk = sqrt (n);
for (int i = 1; i < n; ++i) {
int u, v;
cin >> u >> v;
g[u].eb (v);
g[v].eb (u);
}
dfs1 (1, 0);
dfs2 (1, 1, 1);
while (q--) {
int op, x;
cin >> op >> x;
if (op == 0) {
U (x);
} else {
cout << Q (x) << '\n';
}
}
return 0;
}
:::