题意
传送门 Codeforces 343D
题解
离线处理。将操作按照时间顺序编号为 [ 0 , Q ) [0,Q) [0,Q),那么对于编号为 i i i 的查询操作,只需关注祖先节点及 i i i 本身的操作中,编号区间 [ 0 , i ) [0,i) [0,i) 内最大的灌水操作;与子孙节点及自身的操作中,编号区间 [ 0 , i ) [0,i) [0,i) 内最大的抽水操作;两者中编号最大的即查询的结果。
那么开两颗权值线段树分别维护祖先节点与子孙节点信息;当然,使用 s t d : : s e t std::set std::set 编码更加简单。应用 d s u o n t r e e dsu\ on\ tree dsu on tree,统计子孙节点信息,同时在 D F S DFS DFS 框架下统计祖先节点信息。总时间复杂度 O ( N log 2 N ) O(N\log^2N) O(Nlog2N)。
#include <bits/stdc++.h>
using namespace std;
#define rep(i, l, r) for (int i = l, _ = r; i < _; ++i)
const int maxn = 500005, maxq = 500005, sg_size = 1 << 20;
struct SegmentTree
{
int tree[sg_size];
void init() {
memset(tree, -1, sizeof(tree)); }
void change(int a, int x, int k, int l, int r)
{
if (r - l == 1)
{
tree[k] = x;
return;
}
int chl = (k << 1) + 1, chr = (k << 1) + 2, m = (l + r) >> 1;
a < m ? change(a, x, chl, l, m) : change(a, x, chr, m, r);
tree[k] = max(tree[chl], tree[chr]);
}
int ask(int a, int b, int k, int l, int r)
{
if (a <= l && r <= b)
return tree[k];
int chl = (k << 1) + 1, chr = (k << 1) + 2, m = (l + r) >> 1;
if (b <= m)
return ask(a, b, chl, l, m);
if (m <= a)
return ask(a, b, chr, m, r);
return max(ask(a, b, chl, l, m), ask(a, b, chr, m, r));
}
} P, C;
struct Operation
{
int t, op;
};
int N, Q, sz[maxn], recOp[maxq], Res[maxq];
int clk, L[maxn], R[maxn], vs[maxn];
vector<int> G[maxn];
vector<Operation> O[maxn];
bool hv[maxn];
void rd(int &x)
{
x = 0;
char c = 0;
for (; !isdigit(c); c = getchar())
;
for (; isdigit(c); c = getchar())
x = (x << 1) + (x << 3) + c - '0';
}
void _dfs(int u, int p)
{
sz[u] = 1, vs[clk] = u, L[u] = clk++;
for (auto &v : G[u])
if (v != p)
_dfs(v, u), sz[u] += sz[v];
R[u] = clk;
}
void add_p(int u, bool a)
{
for (auto &o : O[u])
if (o.op == 1)
P.change(o.t, a ? o.t : -1, 0, 0, Q);
}
void add_c(int u, bool a)
{
for (auto &o : O[u])
if (o.op == 2)
C.change(o.t, a ? o.t : -1, 0, 0, Q);
}
void add(int u, int p, bool a)
{
add_c(u, a);
for (auto &v : G[u])
if (v != p && !hv[v])
rep(i, L[v], R[v]) add_c(vs[i], a);
}
void dfs(int u, int p, int keep)
{
add_p(u, 1);
int hvCh = -1, mx = -1;
for (auto &v : G[u])
if (v != p && sz[v] > mx)
mx = sz[v], hvCh = v;
for (auto &v : G[u])
if (v != p && v != hvCh)
dfs(v, u, 0);
if (hvCh != -1)
dfs(hvCh, u, 1), hv[hvCh] = 1;
add(u, p, 1);
for (auto &o : O[u])
if (o.op == 3)
{
int t = o.t;
Res[t] = C.ask(0, t, 0, 0, Q) < P.ask(0, t, 0, 0, Q);
}
if (hvCh != -1)
hv[hvCh] = 0;
if (!keep)
add(u, p, 0);
add_p(u, 0);
}
int main()
{
rd(N);
rep(i, 1, N)
{
int u, v;
rd(u), rd(v);
--u, --v;
G[u].push_back(v), G[v].push_back(u);
}
rd(Q);
rep(i, 0, Q)
{
int op, u;
rd(op), rd(u);
--u;
recOp[i] = op;
O[u].push_back(Operation{
i, op});
}
_dfs(0, -1);
P.init(), C.init();
dfs(0, -1, 1);
rep(i, 0, Q) if (recOp[i] == 3) printf("%d\n", Res[i]);
return 0;
}