zoj-3525 Disappearance

考点

  • 扫描线

题解

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
#include <bits/stdc++.h>
using namespace std;
const int maxn = 2e4 + 50;
int n, cnt, B, W, H;

struct node1 {
int b_, w_, h_, s_;
bool operator<(node1& x) { return b_ < x.b_; }
} arr[maxn];

struct node2 {
int w_, h1_, h2_, flag_;
bool operator<(const node2& x) const {
if (w_ != x.w_) return w_ < x.w_;
return flag_ > x.flag_;
}
} line[maxn];

struct node3 {
int val_, mx_;
} seg[8 * maxn];
#define lson (rt << 1)
#define rson (rt << 1 | 1)
#define val(x) seg[x].val_
#define mx(x) seg[x].mx_

void up(int rt, int l, int r) {
mx(rt) = l == r ? val(rt) : max(mx(lson), mx(rson)) + val(rt);
}

void update(int rt, int l, int r, int L, int R, int v) {
if (L <= l && r <= R) {
val(rt) += v;
up(rt, l, r);
return;
}
int mid = (l + r) / 2;
if (L <= mid) update(lson, l, mid, L, R, v);
if (R > mid) update(rson, mid + 1, r, L, R, v);
up(rt, l, r);
}

int calc(int st, int ed) {
int ltot = 0;
memset(seg, 0, sizeof(seg));
for (int i = st; i <= ed; ++i) {
line[++ltot] = {arr[i].w_, arr[i].h_, arr[i].h_ + H, arr[i].s_};
line[++ltot] = {arr[i].w_ + W, arr[i].h_, arr[i].h_ + H, -arr[i].s_};
}
sort(line + 1, line + 1 + ltot);
int ans = 0;
for (int i = 1; i <= ltot; ++i) {
update(1, 1, 3080, line[i].h1_, line[i].h2_, line[i].flag_);
ans = max(ans, mx(1));
}
return ans;
}

int main() {
while (cin >> n) {
cnt = 0;
int b, w, h, s;
for (int i = 1; i <= n; ++i) {
cin >> b >> w >> h >> s;
if (s >= 0) continue;
b += 1038, w += 1038, h += 1038;
arr[++cnt] = {b, w, h, -s};
}
sort(arr + 1, arr + 1 + cnt);
cin >> B >> W >> H;
if (!cnt) {
cout << "Error 404, mahou shoujo not found!" << endl;
continue;
}
int head = 1, tail = 1, ans = 0;
while (head <= tail && tail <= cnt) {
while (head <= tail && arr[tail].b_ - arr[head].b_ > B) ++head;
while (tail <= cnt && arr[tail].b_ - arr[head].b_ <= B) ++tail;
ans = max(ans, calc(head, tail - 1));
}
cout << -ans << endl;
}
return 0;
}

思路

给你一堆b、w、h的三维权值点,求一个集合,该集合的点满足以下条件:

  • max(b) - min(b) <= B
  • max(w) - min(w) <= W
  • max(h) - min(h) <= H

求这类集合的权值和最小值。


假设只有二维的w和h,那么每个点满足条件的取值范围就是下图整个矩形,

如此一来,就是扫描线的经典板子题,线段树维护区间权值最大即可(这里扫描线应该先增后减)

还剩一个b维度,那就先按b排序;

用双指针规划一块满足尾的b - 头的b <= B的集合,再对该集合执行上述扫描线操作即可。