CodeForces 542B Duck Hunt
首先转化一下,让鸭子不动,猎人往右移动,就相当于开的相邻两枪距离 \(> m\)。
设 \(f_{x, i}\) 为仅考虑 \(r \le x\) 的鸭子,上一次在 \(i\) 开枪,能打到的最大鸭子个数。
\(f_{x - 1} \to f_x\) 时,首先有 \(f_{x, i} = f_{x - 1, i}\)。我们先找到所有 \(r = x\) 的鸭子,设其左端点为 \(l\),将 \(f_{x, l \sim x}\) 区间加 \(1\)。如果在 \(x\) 开枪,有 \(f_{x, x} = \max\limits_{i = 0}^{x - m} f_{x - 1, i}\)。
于是我们需要支持,区间加 \(1\),给单点赋一段前缀 \(\max\)。
但是 \(x\) 高达 \(10^9\),显然我们要优化赋前缀 \(\max\) 的过程。
发现若 \(\max\limits_{i = 0}^{x - m - 1} f_{x, i} < \max\limits_{i = 0}^{x - m} f_{x, i}\),那么 \(f_{x, x - m} > \max\limits_{i = 0}^{x - m - 1} f_{x, i}\)。因为我们区间加 \(1\) 只有 \(O(n)\) 次,所以这样的情况也只会出现 \(O(n)\) 次。考虑出现这种情况的条件:
- 存在一个鸭子,使得它的 \(l = x - m\);
- \(f_{x, x - 2m} > \max\limits_{i = 0}^{x - 2m - 1} f_{x, i}\)。
考虑维护一个堆,同时对 \(x\) 扫描线。对于一个鸭子 \([l, x]\),把 \(l + m\) 扔进堆里,表示在这个位置可能出现上面的情况。对于出现上面情况的 \(x\),再把 \(x + m\) 扔进堆里。
code
#include <bits/stdc++.h>
#define pb emplace_back
#define fst first
#define scd second
#define mkp make_pair
#define mems(a, x) memset((a), (x), sizeof(a))
using namespace std;
typedef long long ll;
typedef double db;
typedef unsigned long long ull;
typedef long double ldb;
typedef pair<ll, ll> pii;
const int maxn = 12000000;
int n, m, N, ls[maxn], rs[maxn], mx[maxn], tag[maxn], rt, ntot;
struct node {
int l, r;
node(int a = 0, int b = 0) : l(a), r(b) {}
};
inline bool operator < (const node &a, const node &b) {
return a.r > b.r || (a.r == b.r && a.l > b.l);
}
inline void pushup(int x) {
mx[x] = max(mx[ls[x]], mx[rs[x]]) + tag[x];
}
void update(int &rt, int l, int r, int ql, int qr, int x) {
if (!rt) {
rt = ++ntot;
}
if (ql <= l && r <= qr) {
mx[rt] += x;
tag[rt] += x;
return;
}
int mid = (l + r) >> 1;
if (ql <= mid) {
update(ls[rt], l, mid, ql, qr, x);
}
if (qr > mid) {
update(rs[rt], mid + 1, r, ql, qr, x);
}
pushup(rt);
}
void modify(int &rt, int l, int r, int x, int y) {
if (!rt) {
rt = ++ntot;
}
if (l == r) {
mx[rt] = y;
return;
}
int mid = (l + r) >> 1;
(x <= mid) ? modify(ls[rt], l, mid, x, y) : modify(rs[rt], mid + 1, r, x, y);
pushup(rt);
}
int query(int rt, int l, int r, int ql, int qr) {
if (!rt || ql > qr) {
return 0;
}
if (ql <= l && r <= qr) {
return mx[rt];
}
int mid = (l + r) >> 1, res = 0;
if (ql <= mid) {
res = max(res, query(ls[rt], l, mid, ql, qr));
}
if (qr > mid) {
res = max(res, query(rs[rt], mid + 1, r, ql, qr));
}
res += tag[rt];
return res;
}
void solve() {
scanf("%d%d", &n, &m);
priority_queue<node> pq;
for (int i = 1, l, r; i <= n; ++i) {
scanf("%d%d", &l, &r);
if (r < 0) {
continue;
}
l = max(0, l);
pq.emplace(l, r);
pq.emplace(-1, l);
N = max(N, r);
}
int lst = -1;
while (pq.size()) {
int l = pq.top().l, r = pq.top().r;
pq.pop();
if (l >= 0) {
update(rt, 0, N, l, r, 1);
continue;
}
if (r == lst) {
continue;
}
int x = lst >= 0 ? query(rt, 0, N, lst, lst) : 0, y = query(rt, 0, N, 0, r - m);
if (l == -1 || y > x) {
lst = r;
modify(rt, 0, N, r, y);
if (r + m <= N) {
pq.emplace(-2, r + m);
}
}
}
printf("%d\n", mx[rt]);
}
int main() {
int T = 1;
// scanf("%d", &T);
while (T--) {
solve();
}
return 0;
}