欢迎来到下蛋爷之家|

下蛋爷

园龄:4年2个月粉丝:8关注:23

CF1017G The Tree 题解

Description

给定一棵树,维护以下 3 个操作:

  1. 1 x 表示如果节点 x 为白色,则将其染黑。否则对这个节点的所有儿子递归进行相同操作。

  2. 2 x 表示将以节点 x 为根的子树染白。

  3. 3 x 表示查询节点 x 的颜色。

n,q105

Solution

首先考虑没有操作二怎么做。

容易发现在点 x 进行的操作能够影响到 y,当且仅当 yx 的子树里且 xy 的路径上进行一操作的总次数不小于路径长度。

那么先将每个点的权值设为 1,进行一次一操作就将操作点点权加 1,则一个点 x 为黑色的条件即为根到 x 的最大后缀和大于等于 0,树剖+线段树维护即可。

加上操作二后,相当于是每次需要将 x 子树内的点权重置为 1,并且还要去除根到 x 这条路径上对 x 子树的影响,前面重置为 1 可以用线段树进行区间覆盖,而去除祖先影响则可以直接求出根到 x 的最大后缀和 s,然后将 x 的点权加上 1s,这样祖先对 x 的贡献就只有 1 了。

时间复杂度:O(n+qlog2n)

Code

#include <bits/stdc++.h>
#define int int64_t
const int kMaxN = 1e5 + 5;
struct Info {
int sum, res;
Info(int _sum = 0, int _res = 0) : sum(_sum), res(_res) {}
friend Info operator +(Info a, Info b) {
return {a.sum + b.sum, std::max(a.res + b.sum, b.res)};
}
};
int n, q;
int p[kMaxN], sz[kMaxN], wson[kMaxN], dfn[kMaxN], top[kMaxN];
std::vector<int> G[kMaxN];
struct SGT {
Info t[kMaxN * 4];
bool tag[kMaxN * 4];
void pushup(int x) {
t[x] = t[x << 1] + t[x << 1 | 1];
}
void addtag(int x, int l, int r) {
tag[x] = 1, t[x] = {-(r - l + 1), -1};
}
void pushdown(int x, int l, int r) {
if (tag[x]) {
int mid = (l + r) >> 1;
addtag(x << 1, l, mid), addtag(x << 1 | 1, mid + 1, r);
tag[x] = 0;
}
}
void build(int x, int l, int r) {
if (l == r) return void(t[x] = {-1, -1});
int mid = (l + r) >> 1;
build(x << 1, l, mid), build(x << 1 | 1, mid + 1, r);
pushup(x);
}
void update1(int x, int l, int r, int ql, int v) {
if (l == r) {
t[x].sum += v, t[x].res += v;
return;
}
pushdown(x, l, r);
int mid = (l + r) >> 1;
if (ql <= mid) update1(x << 1, l, mid, ql, v);
else update1(x << 1 | 1, mid + 1, r, ql, v);
pushup(x);
}
void update2(int x, int l, int r, int ql, int qr) {
if (l > qr || r < ql) return;
else if (l >= ql && r <= qr) return addtag(x, l, r);
pushdown(x, l, r);
int mid = (l + r) >> 1;
update2(x << 1, l, mid, ql, qr), update2(x << 1 | 1, mid + 1, r, ql, qr);
pushup(x);
}
Info query(int x, int l, int r, int ql, int qr) {
if (l > qr || r < ql) return {0, -(int)1e9};
else if (l >= ql && r <= qr) return t[x];
pushdown(x, l, r);
int mid = (l + r) >> 1;
return query(x << 1, l, mid, ql, qr) + query(x << 1 | 1, mid + 1, r, ql, qr);
}
} sgt;
void dfs1(int u, int fa) {
sz[u] = 1;
for (auto v : G[u]) {
if (v == fa) continue;
dfs1(v, u);
sz[u] += sz[v];
if (sz[v] > sz[wson[u]]) wson[u] = v;
}
}
void dfs2(int u, int fa, int t) {
static int cnt = 0;
dfn[u] = ++cnt, top[u] = t;
if (wson[u]) dfs2(wson[u], u, t);
for (auto v : G[u]) {
if (v == fa || v == wson[u]) continue;
dfs2(v, u, v);
}
}
int query(int x) {
if (!x) return 0;
Info ret = {0, -(int)1e9};
for (; x; x = p[top[x]]) ret = sgt.query(1, 1, n, dfn[top[x]], dfn[x]) + ret;
return ret.res;
}
void dickdreamer() {
std::cin >> n >> q;
for (int i = 2; i <= n; ++i) {
std::cin >> p[i];
G[i].emplace_back(p[i]), G[p[i]].emplace_back(i);
}
dfs1(1, 0), dfs2(1, 0, 1), sgt.build(1, 1, n);
for (int i = 1; i <= q; ++i) {
int op, x;
std::cin >> op >> x;
if (op == 1) {
sgt.update1(1, 1, n, dfn[x], 1);
} else if (op == 2) {
sgt.update2(1, 1, n, dfn[x], dfn[x] + sz[x] - 1);
sgt.update1(1, 1, n, dfn[x], -1 - query(x));
} else {
std::cout << (query(x) >= 0 ? "black\n" : "white\n");
}
}
}
int32_t main() {
#ifdef ORZXKR
freopen("in.txt", "r", stdin);
freopen("out.txt", "w", stdout);
#endif
std::ios::sync_with_stdio(0), std::cin.tie(0), std::cout.tie(0);
int T = 1;
// std::cin >> T;
while (T--) dickdreamer();
// std::cerr << 1.0 * clock() / CLOCKS_PER_SEC << "s\n";
return 0;
}
posted @   下蛋爷  阅读(6)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起