P9528 [JOISC 2022] 蚂蚁与方糖 题解

Description

JOI 君是一个生物学家。他准备对蚂蚁和方糖做一些实验。

JOI 君的实验在一个长度为 10910^9 的木条上进行。这根木条被从左往右放置。木条上距离左端点 xx 的点被称作坐标为 xx 的点。

现在,木条上什么都没有。JOI 君将会进行 QQ 次操作。第 ii 个操作 (1iQ)(1 \le i \le Q) 由三个整数 Ti,Xi,AiT_i,X_i,A_i 描述,表示:

  • Ti=1T_i=1,JOI 君在坐标为 XiX_i 的点处放了 AiA_i 个蚂蚁。
  • Ti=2T_i=2,JOI 君在坐标为 XiX_i 的点处放了 AiA_i 块方糖。

由于蚂蚁和方糖都很小,所以可能会有一些蚂蚁和方糖放在同一个点上。JOI 君也可能在同一个点执行多次操作。

这次实验中使用的蚂蚁具有「好奇心强」的萌点。具体地,当 JOI 君拍手时,每个蚂蚁会执行以下操作:

  • 如果存在一块方糖与该蚂蚁距离不超过 LL,它会选择任意一块并吃掉。

可能存在多个蚂蚁同时吃掉一块方糖的情况。

对于每个 kk (1kQ)(1\le k \le Q),JOI 君想要知道以下问题的答案。

  • 假设 JOI 君在第 kk 次操作后拍了一次手,最多有多少块方糖被至少一个蚂蚁吃掉了?

请写一个程序,对于给定的 JOI 君执行的操作和 LL 的值,对于所有 kk 回答 JOI 君的每个问题。

注意 JOI 君并不会真的拍手。因此蚂蚁的位置不会改变,方糖也不会被吃掉。

对于所有数据,满足:

  • 1Q5000001 \le Q \le 500\,000
  • 1L1091 \le L \le 10^9
  • Ti{1,2}T_i \in \{1,2\}
  • 0Xi1090 \le X_i \le 10^9 (1iQ)(1 \le i \le Q)
  • 1Ai1091 \le A_i \le 10^9 (1iQ)(1 \le i \le Q)

Solution

首先可以转化为二分图最大匹配问题,即对于位置在 xx 的蚂蚁,向 [xL,x+R][x-L,x+R] 内的方糖连边,问最大匹配。

跑网络流显然是不行的。这时就要用到 Hall 定理:设左部点集合为 AA,右部点集合为 BB,则最大匹配为 AmaxSA{SNb(S)}\displaystyle|A|-\max_{S\subseteq A}\{|S|-|\text{Nb}(S)|\}

注意到这里的每个左部点连接的是个长度相等的区间,所以用 Hall 定理会很好做。

具体的,选择的左部点集合一定构成若干个区间 [l1,r1],[l2,r2],,[lk,rk][l_1,r_1],[l_2,r_2],\ldots,[l_k,r_k],对应的右部点集合为 [l1L,r1+L],[l2L,r2+L],,[lkL,rk+L][l_1-L,r_1+L],[l_2-L,r_2+L],\ldots,[l_k-L,r_k+L]

容易发现如果存在 [li,ri][l_i,r_i][lj,rj][l_j,r_j] 有交或者 [liL,ri+L][l_i-L,r_i+L][ljL,rj+L][l_j-L,r_j+L] 有交,那么将其合并一定更优。

所以最终的区间一定满足 liri1>2Ll_i-r_{i-1}>2L

pi=cntant1,icntsugar1,i+L,qi=cntant1,i1cntsugar1,i1Lp_i=\text{cntant}_{1,i}-\text{cntsugar}_{1,i+L},q_i=\text{cntant}_{1,i-1}-\text{cntsugar}_{1,i-1-L},则一个区间 [l,r][l,r] 的贡献为 prqlp_r-q_l


现在问题转化为了选择 kk 个区间,要求最大化 i=1k(priqli)\sum_{i=1}^{k}{(p_{r_i}-q_{l_i})}。单次询问可以 dp 做。

考虑用线段树维护上面的那个 dp,设 fx,0/1,0/1f_{x,0/1,0/1} 表示 xx 对应的区间,选的第一个为 ll 还是 rr,最后一个是 ll 还是 rr

如果在 xx 处加入 cc 个蚂蚁,那么变化为:[x,+][x,+\infty]pip_icic_i[x+1,+][x+1,+\infty]qiq_icic_i。转换一下,变为 pxp_xcic_i[x+1,+][x+1,+\infty]pip_iqiq_i 同时加 cic_i

前面的是单点修改,后面的 44 种 dp 最优选法一定不变,打个标记即可。

如果在 xx 处加入 cc 块方糖,变化为:[xL,x+L][x-L,x+L]pip_ici-c_i[x+L+1,+][x+L+1,+\infty]pip_iqiq_i 同时加 ci-c_i

后面的和上面是一样的。由于最优方案一定满足 rili1>2Lr_i-l_{i-1}>2L,所以 [xL,x+R][x-L,x+R] 内部的四种 dp 的最优方案选的点数也是确定的,同样打标记即可。

具体见代码。

时间复杂度:O(QlogQ)O(Q\log Q)

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
#include <bits/stdc++.h>

#define int int64_t

using pii = std::pair<int, int>;

const int kMaxN = 5e5 + 5;

int n, m, L;
int op[kMaxN], x[kMaxN], c[kMaxN], unq[kMaxN];

struct Node {
int LL, LR, RL, RR;
friend Node operator +(const Node &n1, const Node n2) {
static Node ret;
ret.LL = std::max({n1.LL, n2.LL, n1.LL + n2.RL, n1.LR + n2.LL});
ret.LR = std::max({n1.LR, n2.LR, n1.LL + n2.RR, n1.LR + n2.LR});
ret.RL = std::max({n1.RL, n2.RL, n1.RL + n2.RL, n1.RR + n2.LL});
ret.RR = std::max({n1.RR, n2.RR, n1.RL + n2.RR, n1.RR + n2.LR});
return ret;
}
};

struct SGT {
Node t[kMaxN * 4];
std::array<int, 4> tag[kMaxN * 4];
void pushup(int x) {
t[x] = t[x << 1] + t[x << 1 | 1];
}
void addtag(int x, std::array<int, 4> v) {
t[x].LL += v[0], t[x].LR += v[1], t[x].RL += v[2], t[x].RR += v[3];
tag[x][0] += v[0], tag[x][1] += v[1], tag[x][2] += v[2], tag[x][3] += v[3];
}
void pushdown(int x) {
if (tag[x][0] || tag[x][1] || tag[x][2] || tag[x][3]) {
addtag(x << 1, tag[x]), addtag(x << 1 | 1, tag[x]);
tag[x] = {0, 0, 0, 0};
}
}
void update(int x, int l, int r, int ql, int qr, std::array<int, 4> 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);
}
} sgt;

int getid(int x) { return std::lower_bound(unq + 1, unq + 1 + m, x) - unq; }

void discrete() {
std::sort(unq + 1, unq + 1 + m);
m = std::unique(unq + 1, unq + 1 + m) - (unq + 1);
}

void dickdreamer() {
std::cin >> n >> L;
for (int i = 1; i <= n; ++i) {
std::cin >> op[i] >> x[i] >> c[i];
unq[++m] = x[i];
}
discrete();
int tot = 0;
for (int i = 1; i <= n; ++i) {
if (op[i] == 1) {
int id = getid(x[i]);
sgt.update(1, 1, m, id, id, {0, c[i], 0, c[i]});
sgt.update(1, 1, m, id + 1, m, {-c[i], 0, 0, c[i]});
tot += c[i];
} else {
int id1 = getid(x[i] - L), id2 = getid(x[i] + L + 1);
sgt.update(1, 1, m, id1, id2 - 1, {0, -c[i], 0, -c[i]});
sgt.update(1, 1, m, id2, m, {c[i], 0, 0, -c[i]});
}
std::cout << tot - std::max<int>(sgt.t[1].LR, 0) << '\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;
}

P9528 [JOISC 2022] 蚂蚁与方糖 题解
https://sobaliuziao.github.io/2025/04/02/post/e80d61c0.html
作者
Egg_laying_master
发布于
2025年4月2日
许可协议