题解-LibreOJ-6498「雅礼集训 2018 Day2」农民

题目概括征集中~ @oy么么哒

神仙码量题。

观察题意,进行问题转化。对于树上每一条边,可以通过它的肥料权值必定是一段区间:若这条边连接父节点与左儿子,则对应区间为 $(-\infty,a[\text{fa}])$;反之,则为 $(a[\text{fa}], \infty)$。

因此,我们需要维护一棵线段树,每个节点存储状态值 0/1 以及权值 val 。需要支持以下操作:

  1. 单点权值修改
  2. 区间状态值翻转
  3. 区间查询状态为 0/1 的最值

具体地,在线段树的每个节点上维护 max0, min0, max1, min1 。区间状态值翻转则只需交换 max0, max1 和 min0, min1。区间查询与单点修改不再赘述。

对二叉树进行树链剖分,每次查询只需查找该节点到根节点的限制范围;若该节点权值在范围之内,则可以吸收到肥料,反之不能。

注意:线段树的 max、min需要赋极值作为初值;交换时需理清变量所代表的意义

代码实现细节极多,尤其是线段树异常毒瘤。

代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
#include<bits/stdc++.h>
using namespace std;
#define lson(u) node[u].l
#define rson(u) node[u].r
#define val(u) node[u].val
#define tag(u) node[u].tag

const int maxn = 100005;
const int inf = 0x3f3f3f3f;

struct Node {
int l, r, val[2][2];
int tag;
}node[maxn * 3];
int cnt = 0, R;
pair<int, int> t[maxn];

inline void pushdown(int u) {
if (tag(u)) {
swap(val(lson(u))[0][0], val(lson(u))[1][0]);
swap(val(lson(u))[0][1], val(lson(u))[1][1]);
swap(val(rson(u))[0][0], val(rson(u))[1][0]);
swap(val(rson(u))[0][1], val(rson(u))[1][1]);
tag(lson(u)) ^= 1, tag(rson(u)) ^= 1;
tag(u) = 0;
}
}

inline void pushup(int u) {
val(u)[0][0] = min(val(lson(u))[0][0], val(rson(u))[0][0]);
val(u)[0][1] = max(val(lson(u))[0][1], val(rson(u))[0][1]);
val(u)[1][0] = min(val(lson(u))[1][0], val(rson(u))[1][0]);
val(u)[1][1] = max(val(lson(u))[1][1], val(rson(u))[1][1]);
}

void build(int& u, int l, int r) {
u = ++cnt;
val(u)[0][0] = val(u)[1][0] = inf;
val(u)[0][1] = val(u)[1][1] = -inf;
if (l == r) {
int d = t[l].first, w = t[l].second;
val(u)[d][0] = val(u)[d][1] = w;
return;
}
int mid = (l + r) >> 1;
build(lson(u), l, mid);
build(rson(u), mid + 1, r);
pushup(u);
}

void modify_range_reverse(int u, int l, int r, int ql, int qr) {
if (ql <= l && r <= qr) {
swap(val(u)[0][0], val(u)[1][0]);
swap(val(u)[0][1], val(u)[1][1]);
tag(u) ^= 1;
return;
}
pushdown(u);
int mid = (l + r) >> 1;
if (ql <= mid) modify_range_reverse(lson(u), l, mid, ql, qr);
if (mid < qr) modify_range_reverse(rson(u), mid + 1, r, ql, qr);
pushup(u);
}

void modify_point(int u, int l, int r, int p, int val) {
if (l == r) {
if (val(u)[0][0] != inf) val(u)[0][0] = val(u)[0][1] = val;
else val(u)[1][0] = val(u)[1][1] = val;
return;
}
pushdown(u);
int mid = (l + r) >> 1;
if (p <= mid) modify_point(lson(u), l, mid, p, val);
else modify_point(rson(u), mid + 1, r, p, val);
pushup(u);
}

pair<int, int> query_range(int u, int l, int r, int ql, int qr) {
// first: 1:max
// second: 0:min
if (ql <= l && r <= qr)
return make_pair(val(u)[1][1], val(u)[0][0]);
pushdown(u);
int mid = (l + r) >> 1;
int first = -inf, second = inf;
if (ql <= mid) {
pair<int, int> t = query_range(lson(u), l, mid, ql, qr);
first = max(first, t.first);
second = min(second, t.second);
}
if (mid < qr) {
pair<int, int> t = query_range(rson(u), mid + 1, r, ql, qr);
first = max(first, t.first);
second = min(second, t.second);
}
return make_pair(first, second);
}

int N, M;
vector<int> G[maxn];
int fa[maxn];
int dir[maxn], w[maxn];
int dep[maxn], size[maxn], son[maxn];
int top[maxn], dfn[maxn], dfn_idx;

void dfs1(int u) {
dep[u] = dep[fa[u]] + 1;
size[u] = 1;
for (vector<int>::iterator it = G[u].begin(); it != G[u].end(); it++) {
int v = *it;
dfs1(v);
size[u] += size[v];
if (size[v] > size[son[u]]) son[u] = v;
}
}

void dfs2(int u, int topc) {
dfn[u] = ++dfn_idx;
t[dfn[u]] = make_pair(dir[u], w[fa[u]]);
top[u] = topc;
if (son[u]) dfs2(son[u], topc);
for (vector<int>::iterator it = G[u].begin(); it != G[u].end(); it++) {
int v = *it;
if (v == son[u]) continue;
dfs2(v, v);
}
}

int main() {
scanf("%d%d", &N, &M);
for (int i = 1; i <= N; ++i) {
int x, y;
scanf("%d%d%d", &w[i], &x, &y);
dir[x] = 0, dir[y] = 1;
fa[x] = fa[y] = i;
if (x) G[i].push_back(x);
if (y) G[i].push_back(y);
}
dfs1(1);
dfs2(1, 1);
build(R, 1, N);
while (M--) {
int op, x, y;
scanf("%d%d", &op, &x);
if (op == 1) {
scanf("%d", &y);
for (vector<int>::iterator it = G[x].begin(); it != G[x].end(); it++) {
int v = *it;
modify_point(R, 1, N, dfn[v], y);
}
w[x] = y;
} else if (op == 2) {
modify_range_reverse(R, 1, N, dfn[x], dfn[x] + size[x] - 1);
modify_range_reverse(R, 1, N, dfn[x], dfn[x]);
} else {
int val = w[x];
int first = -inf, second = inf;
while (top[x] != 1) {
pair<int, int> t = query_range(R, 1, N, dfn[top[x]], dfn[x]);
first = max(first, t.first);
second = min(second, t.second);
x = fa[top[x]];
}
if (x != 1) {
pair<int, int> t = query_range(R, 1, N, 2, dfn[x]);
first = max(first, t.first);
second = min(second, t.second);
}
if (val > first && val < second) puts("YES");
else puts("NO");
}
}
return 0;
}

Comments

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×