标准意义上第一道非模板树剖题,虽然我并不认为它是树剖
另:这是一道水题,第二道本省省选题(菜的一批)
Description
题意简述:给一棵树,支持两种操作:
1.对一个节点打标记
2.求一个节点距离最近的直系祖先(就是根到它链上的那种节点)
定义:自己也算自己的祖先
Solution
\[Begin\]
首先树和序列转化,求一波 \(dfn\) 序
整一棵线段树,维护这个序列
修改的时候就变成了了区间取 \(max\),这里不是那种纯 \(max\)
如果询问就变成了单点查询
这里有一个问题:我们在 \(push\_down\) (或者你叫它 \(spread\))的时候要取的是 \(max\),但是我们在 \(push\_up\) 的时候是维护的子树上面最小的深度编号
这样有点玄学剪枝的意味,但是正确性可以意会(毕竟是先取 \(max\) 再取 \(min\) )
\[Q.A.D\]
\(P.S.\) 博主知道是\(QED\)
(为啥我觉得不是树剖??)
Code
#include <bits/stdc++.h>
using namespace std;
#define int long long
namespace yspm {
inline int read() {
int res = 0, f = 1;
char k;
while (!isdigit(k = getchar()))
if (k == '-')
f = -1;
while (isdigit(k)) res = res * 10 + k - '0', k = getchar();
return res * f;
}
const int N = 1e5 + 10;
struct node {
int l, r, maxx, add;
#define add(p) t[p].add
#define l(p) t[p].l
#define r(p) t[p].r
#define maxx(p) t[p].maxx
} t[N << 2];
struct edge {
int to, nxt;
} e[N << 1];
int head[N], cnt, tim, id[N], dep[N], sz[N], son[N], top[N], fa[N], n, T;
inline void adde(int u, int v) {
e[++cnt].nxt = head[u];
e[cnt].to = v;
return head[u] = cnt, void();
}
inline void dfs1(int x, int f) {
fa[x] = f;
dep[x] = dep[f] + 1;
sz[x] = 1;
for (int i = head[x]; i; i = e[i].nxt) {
int t = e[i].to;
if (t == f)
continue;
dfs1(t, x);
sz[x] += sz[t];
if (sz[t] > sz[son[x]])
son[x] = t;
}
return;
}
inline void dfs2(int x, int topf) {
id[x] = ++tim;
top[x] = topf;
if (!son[x])
return;
dfs2(son[x], topf);
for (int i = head[x]; i; i = e[i].nxt) {
int t = e[i].to;
if (t == fa[x] || t == son[x])
continue;
dfs2(t, t);
}
return;
}
inline void push_up(int p) {
maxx(p) = dep[maxx(p << 1)] < dep[maxx(p << 1 | 1)] ? maxx(p << 1) : maxx(p << 1 | 1);
return;
}
inline void spread(int p) {
if (add(p)) {
maxx(p << 1) = dep[maxx(p << 1)] > dep[add(p)] ? maxx(p << 1) : add(p);
maxx(p << 1 | 1) = dep[maxx(p << 1 | 1)] > dep[add(p)] ? maxx(p << 1 | 1) : add(p);
add(p << 1) = dep[add(p << 1)] > dep[add(p)] ? add(p << 1) : add(p);
add(p << 1 | 1) = dep[add(p << 1 | 1)] > dep[add(p)] ? add(p << 1 | 1) : add(p);
}
return add(p) = 0, void();
}
inline void build(int p, int l, int r) {
l(p) = l;
r(p) = r;
if (l == r)
return;
int mid = (l + r) >> 1;
build(p << 1, l, mid);
build(p << 1 | 1, mid + 1, r);
return push_up(p);
}
inline void change(int p, int l, int r, int d) {
if (l <= l(p) && r(p) <= r) {
maxx(p) = dep[maxx(p)] > dep[d] ? maxx(p) : d;
add(p) = dep[add(p)] > dep[d] ? add(p) : d;
return void();
}
spread(p);
int mid = (l(p) + r(p)) >> 1;
if (l <= mid)
if (dep[d] > dep[maxx(p << 1)])
change(p << 1, l, r, d);
if (r > mid)
if (dep[d] > dep[maxx(p << 1 | 1)])
change(p << 1 | 1, l, r, d);
return push_up(p);
}
inline int query(int p, int x) {
if (l(p) == x && r(p) == x)
return maxx(p);
spread(p);
int mid = (l(p) + r(p)) >> 1, ans = -1;
if (x <= mid)
return query(p << 1, x);
else
return query(p << 1 | 1, x);
}
signed main() {
n = read(), T = read();
for (int i = 1, u, v; i < n; ++i) u = read(), v = read(), adde(u, v);
dfs1(1, 0), dfs2(1, 1), build(1, 1, n);
change(1, id[1], id[1] + sz[1] - 1, 1);
while (T--) {
string s;
cin >> s;
int x = read();
if (s[0] == 'Q')
printf("%lld\n", query(1, id[x]));
if (s[0] == 'C')
change(1, id[x], id[x] + sz[x] - 1, x);
}
return 0;
}
} // namespace yspm
signed main() { return yspm::main();
原文地址:https://www.cnblogs.com/yspm/p/12382273.html
时间: 2024-10-30 12:06:59