poj-2482 Stars in Your Window

考点

  • 扫描线

题解

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
#include <algorithm>
#include <cstring>
#include <iostream>
using namespace std;
typedef long long ll;
const int maxn = 1e4 + 50;
ll n, w, h, ltot, ytot, dy[2 * maxn];

struct node1 {
ll x_, y1_, y2_, v_;
node1(ll x = 0, ll y1 = 0, ll y2 = 0, ll v = 0)
: x_(x), y1_(y1), y2_(y2), v_(v) {}
bool operator<(node1 &x) {
if (x_ != x.x_) return x_ < x.x_;
return v_ > x.v_;
}
} line[2 * maxn];

struct node2 {
ll lz_, mx_;
} seg[8 * maxn];
#define lson (rt << 1)
#define rson (rt << 1 | 1)
#define lz(x) seg[x].lz_
#define mx(x) seg[x].mx_

void down(ll rt) {
if (lz(rt)) {
lz(lson) += lz(rt), lz(rson) += lz(rt);
mx(lson) += lz(rt), mx(rson) += lz(rt);
lz(rt) = 0;
}
}

void up(ll rt) { mx(rt) = max(mx(lson), mx(rson)); }

void update(ll rt, ll l, ll r, ll L, ll R, ll v) {
if (L <= l && r <= R) {
lz(rt) += v, mx(rt) += v;
return;
}
down(rt);
ll 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);
}

int main() {
ll x, y, v, y1, y2;
while (cin >> n >> w >> h) {
ll ans = 0;
ltot = ytot = 0, memset(seg, 0, sizeof(seg));
for (ll i = 1; i <= n; ++i) {
cin >> x >> y >> v;
y1 = y + 1, y2 = y + h;
dy[++ytot] = y1, dy[++ytot] = y2;
line[++ltot] = node1(x + 1, y1, y2, v),
line[++ltot] = node1(x + w, y1, y2, -v);
}
sort(dy + 1, dy + 1 + ytot), sort(line + 1, line + 1 + ltot);
ytot = unique(dy + 1, dy + 1 + ytot) - 1 - dy;
for (ll i = 1; i <= ltot; ++i) {
y1 = lower_bound(dy + 1, dy + 1 + ytot, line[i].y1_) - dy;
y2 = lower_bound(dy + 1, dy + 1 + ytot, line[i].y2_) - dy;
update(1, 1, ytot, y1, y2, line[i].v_);
ans = max(ans, mx(1));
}
cout << ans << endl;
}
return 0;
}

思路

先上图。

其中有两个注意点:

  1. 并不需要挪点,我自己用的就是(x+1, y+1)(x+w, y+h),这样更好理解。

  2. 若扫描线重合,先增后减。如下图所示,a + b才是真正的可取范围;

    一旦先减后增,则可取范围变成ab,是错误的。

  3. 这是采用的是扫描线的思想,线段树维护的是每个点的最大值,而并非段;所以必须要用懒标记!