P9530 [JOISC2022] 鱼 2 题解

Description

JOI 君有 NN 条鱼,编号为 1,2,,N1,2,\dots,N。第 ii (1iN)(1 \le i \le N) 条鱼的大小为 AiA_i

当我们养鱼的时候,需要注意如下的一个事实:如果有两条鱼离得很近,那么随着时间的流逝,可能会有其中一条吃掉另一条。其中,两条鱼离得很近,当且仅当它们中间没有鱼。
更具体地,如果鱼 xx 的大小不小于鱼 yy 的大小,且鱼 x,yx,y 离得很近,那么 xx 可以吃掉 yy,且 xx 的大小变为原来 x,yx,y 的大小之和。如果 x,yx,y 一样大,那么 xx 吃掉 yyyy 吃掉 xx 都可能发生。

JOI 君会养 QQ 天鱼。为了消磨时光,他会进行如下的思想实验。在第 jj(1jQ)(1 \le j \le Q),JOI 君会进行如下行动中的一个:

  • 第一类:JOI 君给鱼 XjX_j 吃了某些秘制的食物。这会将鱼 XjX_j 的大小变为 YjY_j

  • 第二类:JOI 君将编号在区间 [Lj,Rj][L_j,R_j] 内的鱼单独拿出来,并进行以下实验:
    JOI 君将鱼 Lj,Lj+1,,RjL_j,L_j+1,\dots,R_j 从左到右依次放在一个鱼缸中。由于鱼们具有如上所述的特点,最后只有一条鱼会存活。存活的这条鱼的编号取决于在哪些时刻哪些鱼吃掉了哪些鱼。JOI 君想知道可能成为最后存活者的鱼的条数。在实验中,鱼的编号不会改变,也不能有两条鱼同时吃掉同一条鱼。

请写一个程序,对于给定的 JOI 君的鱼和实验的信息,计算每个第二类行动的答案来让 JOI 君能够证明或证伪自己的观点。注意这只是思想实验,并没有任何鱼真的被吃掉。

【数据范围】

对于所有数据,满足:

  • 1N,Q1000001 \le N,Q \le 100\,000
  • 1Ai1091 \le A_i \le 10^9 (1iN)(1\le i\le N)
  • Tj{1,2}T_j \in \{1,2\}
  • 1XjN1 \le X_j \le N (1jQ)(1\le j\le Q)
  • 1Yj1091 \le Y_j \le 10^9
  • 1LjRjN1 \le L_j \le R_j \le N (1jQ)(1 \le j \le Q)

Solution

先假设询问区间为 [1,n][1,n]

首先直接判断一条鱼 xx 是否有解是不好做的,考虑判断是否无解。

容易发现如果存在一个区间 [l,r][l,r],满足 l<x<rl<x<r 并且 suml+1,r1<min{al,ar}sum_{l+1,r-1}<\min\{a_l,a_r\} 就说明 xx 一定无法突破 [l,r][l,r] 的限制,也就是无解。并且如果 xx 不被任何一个这样的 [l,r][l,r] 包含就一定有解。

直接枚举每个 [l,r][l,r] 显然无法接受,但有个结论是总共最多 O(nlogV)O(n\log V) 个这样的区间。证明就考虑假设存在两个区间 [l,r1][l,r_1][l,r2][l,r_2] 满足性质,那么 suml+1,r2>2suml+1,r21>2suml+1,r1sum_{l+1,r_2}>2\cdot sum_{l+1,r_2-1}>2\cdot sum_{l+1,r_1},所以对于每个 ll 只存在 O(logV)O(\log V) 个符合条件的 rr,总个数也就是 O(nlogV)O(n\log V)。同样可以证明包含任意一点的线段数也是 O(logV)O(\log V) 的,这里就不证了。

快速找到这些线段可以使用线段树二分。询问时相当于问有多少个点没有被线段覆盖,同样用线段树维护即可。

对于修改 (x,y)(x,y) 就暴力删去与 xx 有关的线段,修改后再加入。


然后考虑询问为任意区间的情况。

不妨设询问为 [L,R][L,R],那么对于全局的一个线段 [l,r][l,r] 满足 LlrRL\leq l\leq r\leq R 或者 lLrRl\leq L\leq r\leq RLlRrL\leq l\leq R\leq r 的话这个线段一定能造成贡献,而如果 [l,r][l,r] 完全包含 [L,R][L,R] 就说明 [l,r][l,r] 不能造成贡献,找到这些线段再去掉即可。

时间复杂度:O((n+q)lognlogV)O\left((n+q)\log n\log V\right)

Code

Code
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
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
#include <bits/stdc++.h>

#define int int64_t

const int kMaxN = 1e5 + 5;

int n, q;
int a[kMaxN];
std::set<std::pair<int, int>> st;
std::vector<int> vl[kMaxN], vr[kMaxN];

struct BIT {
int c[kMaxN];

void upd(int x, int v) {
for (; x <= n; x += x & -x) c[x] += v;
}

int qry(int x) {
int ret = 0;
for (; x; x -= x & -x) ret += c[x];
return ret;
}
} bit;

struct SGT1 {
int mx1[kMaxN * 4], tag1[kMaxN * 4];
int mx2[kMaxN * 4], tag2[kMaxN * 4];

void pushup(int x) {
mx1[x] = std::max(mx1[x << 1], mx1[x << 1 | 1]);
mx2[x] = std::max(mx2[x << 1], mx2[x << 1 | 1]);
}

void addtag(int x, int v1, int v2) {
mx1[x] += v1, tag1[x] += v1;
mx2[x] += v2, tag2[x] += v2;
}

void pushdown(int x) {
if (tag1[x] || tag2[x]) {
addtag(x << 1, tag1[x], tag2[x]), addtag(x << 1 | 1, tag1[x], tag2[x]);
tag1[x] = tag2[x] = 0;
}
}

void update(int x, int l, int r, int ql, int qr, int v1, int v2) {
if (l > qr || r < ql) return;
else if (l >= ql && r <= qr) return addtag(x, v1, v2);
pushdown(x);
int mid = (l + r) >> 1;
update(x << 1, l, mid, ql, qr, v1, v2), update(x << 1 | 1, mid + 1, r, ql, qr, v1, v2);
pushup(x);
}

int getpos1(int x, int l, int r, int ql, int qr, int v) {
if (l > qr || r < ql || mx1[x] <= v || ql > qr) return 0;
else if (l >= ql && r <= qr) {
if (l != r) pushdown(x);
int mid = (l + r) >> 1;
if (l == r) return l;
else return mx1[x << 1 | 1] > v ? getpos1(x << 1 | 1, mid + 1, r, ql, qr, v) : getpos1(x << 1, l, mid, ql, qr, v);
}
pushdown(x);
int mid = (l + r) >> 1, R = getpos1(x << 1 | 1, mid + 1, r, ql, qr, v);
if (R) return R;
else return getpos1(x << 1, l, mid, ql, qr, v);
}

int getpos2(int x, int l, int r, int ql, int qr, int v) {
if (l > qr || r < ql || mx2[x] <= v || ql > qr) return 0;
else if (l >= ql && r <= qr) {
if (l != r) pushdown(x);
int mid = (l + r) >> 1;
if (l == r) return l;
else return mx2[x << 1] > v ? getpos2(x << 1, l, mid, ql, qr, v) : getpos2(x << 1 | 1, mid + 1, r, ql, qr, v);
}
pushdown(x);
int mid = (l + r) >> 1, L = getpos2(x << 1, l, mid, ql, qr, v);
if (L) return L;
else return getpos2(x << 1 | 1, mid + 1, r, ql, qr, v);
}
} sgt1;

struct SGT2 {
int mi[kMaxN * 4], cnt[kMaxN * 4], tag[kMaxN * 4];

void pushup(int x) {
mi[x] = std::min(mi[x << 1], mi[x << 1 | 1]);
cnt[x] = 0;
if (mi[x << 1] == mi[x]) cnt[x] += cnt[x << 1];
if (mi[x << 1 | 1] == mi[x]) cnt[x] += cnt[x << 1 | 1];
}

void addtag(int x, int v) {
mi[x] += v, tag[x] += v;
}

void pushdown(int x) {
if (tag[x]) {
addtag(x << 1, tag[x]), addtag(x << 1 | 1, tag[x]);
tag[x] = 0;
}
}

void build(int x, int l, int r) {
cnt[x] = r - l + 1;
if (l == r) return;
int mid = (l + r) >> 1;
build(x << 1, l, mid), build(x << 1 | 1, mid + 1, r);
}

void update(int x, int l, int r, int ql, int qr, int v) {
if (l > qr || r < ql) return;
else if (l >= ql && r <= qr) return addtag(x, v);
pushdown(x);
int mid = (l + r) >> 1;
update(x << 1, l, mid, ql, qr, v), update(x << 1 | 1, mid + 1, r, ql, qr, v);
pushup(x);
}

std::pair<int, int> query(int x, int l, int r, int ql, int qr) {
if (l > qr || r < ql) return {1e9, 0};
else if (l >= ql && r <= qr) return {mi[x], cnt[x]};
pushdown(x);
int mid = (l + r) >> 1;
auto L = query(x << 1, l, mid, ql, qr), R = query(x << 1 | 1, mid + 1, r, ql, qr);
if (L.first == R.first) return {L.first, L.second + R.second};
else return std::min(L, R);
}
} sgt2;

void ins(int l, int r) {
if (r - l + 1 != 1 && !st.count({l, r})) {
sgt2.update(1, 1, n, l + 1, r - 1, 1);
st.emplace(l, r);
}
}

void del(int l, int r) {
if (r - l + 1 == 1 || !st.count({l, r})) return;
sgt2.update(1, 1, n, l + 1, r - 1, -1);
st.erase({l, r});
}

std::vector<std::pair<int, int>> getseg(int x) {
std::vector<std::pair<int, int>> vl, vr, seg;
int s1 = bit.qry(x), s2 = -bit.qry(x - 1);
for (int p = sgt1.getpos1(1, 1, n, 1, x - 1, s1); p; p = sgt1.getpos1(1, 1, n, 1, p - 1, s1)) {
vl.emplace_back(p, s1 - bit.qry(p));
}
for (int p = sgt1.getpos2(1, 1, n, x + 1, n, s2); p; p = sgt1.getpos2(1, 1, n, p + 1, n, s2)) {
vr.emplace_back(p, bit.qry(p - 1) - s1);
}
for (auto [p1, s1] : vl) {
for (auto [p2, s2] : vr) {
if (a[p1] > s1 + s2 && a[p2] > s1 + s2) {
seg.emplace_back(p1, p2);
}
}
}
return seg;
}

std::vector<std::pair<int, int>> getsegs(int x) {
std::vector<std::pair<int, int>> seg;
for (auto [l, r] : st)
if (l < x && x < r)
seg.emplace_back(l, r);
return seg;
}

std::vector<std::pair<int, int>> getsegl(int x) {
std::vector<std::pair<int, int>> vec;
int s = -bit.qry(x);
for (int p = sgt1.getpos2(1, 1, n, x + 1, n, s); p; p = sgt1.getpos2(1, 1, n, p + 1, n, s)) {
int sum = bit.qry(p - 1) + s;
if (sum < a[x] && sum < a[p]) vec.emplace_back(x, p);
}
return vec;
}

std::vector<std::pair<int, int>> getsegr(int x) {
std::vector<std::pair<int, int>> vec;
int s = bit.qry(x - 1);
for (int p = sgt1.getpos1(1, 1, n, 1, x - 1, s); p; p = sgt1.getpos1(1, 1, n, 1, p - 1, s)) {
int sum = s - bit.qry(p);
if (sum < a[x] && sum < a[p]) vec.emplace_back(p, x);
}
return vec;
}

void prework() {
for (int i = 1; i <= n; ++i) {
sgt1.update(1, 1, n, i, i, a[i], a[i]);
sgt1.update(1, 1, n, i, n, a[i], 0);
sgt1.update(1, 1, n, i + 1, n, 0, -a[i]);
bit.upd(i, a[i]);
}
sgt2.build(1, 1, n);
for (int i = 2; i < n; ++i) {
auto vec = getseg(i);
for (auto [l, r] : vec) ins(l, r);
}
}

void update(int x, int y) {
auto segs = getseg(x);
for (auto [l, r] : segs) del(l, r);
if (x < n - 1) {
auto seg = getsegl(x);
for (auto [l, r] : seg) del(l, r);
}
if (x > 2) {
auto seg = getsegr(x);
for (auto [l, r] : seg) del(l, r);
}

bit.upd(x, y - a[x]);
sgt1.update(1, 1, n, x, x, y - a[x], y - a[x]);
sgt1.update(1, 1, n, x, n, y - a[x], 0);
sgt1.update(1, 1, n, x + 1, n, 0, -(y - a[x]));
a[x] = y;

auto seg1 = getseg(x);
for (auto [l, r] : seg1) ins(l, r);
if (x < n - 1) {
auto seg = getsegl(x);
for (auto [l, r] : seg) ins(l, r);
}
if (x > 2) {
auto seg = getsegr(x);
for (auto [l, r] : seg) ins(l, r);
}
}

int query(int l, int r) {
std::vector<std::pair<int, int>> vec, tmp;
auto segs = getseg(l);
for (auto [ll, rr] : segs)
if (rr > r)
vec.emplace_back(ll, rr);
for (auto [l, r] : vec) sgt2.update(1, 1, n, l + 1, r - 1, -1);

int s1 = bit.qry(r), s2 = -bit.qry(l - 1);

for (int p = sgt1.getpos1(1, 1, n, l, r - 1, s1); p; p = sgt1.getpos1(1, 1, n, l, p - 1, s1)) {
tmp.emplace_back(p, r + 1);
sgt2.update(1, 1, n, p + 1, r, 1);
}

for (int p = sgt1.getpos2(1, 1, n, l + 1, r, s2); p; p = sgt1.getpos2(1, 1, n, p + 1, r, s2)) {
tmp.emplace_back(l - 1, p);
sgt2.update(1, 1, n, l, p - 1, 1);
}

auto p = sgt2.query(1, 1, n, l, r);
for (auto [l, r] : vec) sgt2.update(1, 1, n, l + 1, r - 1, 1);
for (auto [l, r] : tmp) sgt2.update(1, 1, n, l + 1, r - 1, -1);
if (!p.first) return p.second;
else return 0;
}

void dickdreamer() {
std::cin >> n;
for (int i = 1; i <= n; ++i) std::cin >> a[i];
prework();
std::cin >> q;
for (int i = 1; i <= q; ++i) {
int op, l, r;
std::cin >> op >> l >> r;
if (op == 1) update(l, r);
else std::cout << query(l, r) << '\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;
}

P9530 [JOISC2022] 鱼 2 题解
https://sobaliuziao.github.io/2024/08/18/post/8ddf90ff.html
作者
Egg_laying_master
发布于
2024年8月18日
许可协议