B. Beam Cannon【2014上海邀请赛】
B. Beam Cannon
题意:
给 \(n\) 个点和一个长 \(W\) 宽 \(H\) 的矩形,问平移这个矩形最多能覆盖多少个点
思路:
对于每一个点,考虑什么样的矩形能覆盖它,考虑矩形的中心点就可以,这样一个点对应一个矩形,然后就是求 \(n\) 个矩形覆盖次数最多的区域
用线段树区间查最大就可以
#include<bits/stdc++.h>
#define mid (l+r>>1)
#define lo (o<<1)
#define ro (o<<1|1)
using namespace std;
typedef long long ll;
const int N = 4e4 + 10;
int len[N << 2], tag[N << 2], mx[N << 2];
int n, w, h;
int nums[N], cnt;
void init() {
cnt = 0;
memset(len, 0, sizeof len);
memset(tag, 0, sizeof tag);
memset(mx, 0, sizeof mx);
}
struct line {
int l, r, h, tag;
bool operator < (const line& b)const {
if (h != b.h) return h < b.h;
return tag > b.tag;
}
}L[N];
int ans;
void push_down(int o, int l, int r) {
if (!tag[o])return;
tag[lo] += tag[o]; tag[ro] += tag[o];
mx[lo] += tag[o]; mx[ro] += tag[o];
tag[o] = 0;
}
void updt(int L, int R, int v, int o = 1, int l = 1, int r = cnt) {
if (L <= l and r <= R) {
tag[o] += v;
mx[o] += v;
return;
}
push_down(o, l, r);
if (L <= mid)updt(L, R, v, lo, l, mid);
if (R > mid)updt(L, R, v, ro, mid + 1, r);
mx[o] = max(mx[lo], mx[ro]);
}
int main() {
#ifndef ONLINE_JUDGE
freopen("in.txt","r",stdin);
#endif
while (~scanf("%d", &n) and n != -1) {
scanf("%d%d", &w, &h);
init();
for (int i = 1; i <= n; i++) {
int x, y; scanf("%d%d", &x, &y);
int lx = x - w / 2, rx = x + w / 2;
int ly = y - h / 2, ry = y + h / 2;
if (w & 1)lx--; if (h & 1)ly--;
//printf("%d %d %d %d\n", lx, ly, rx, ry);
nums[++cnt] = lx, nums[++cnt] = rx;
L[i * 2 - 1] = { lx,rx,ly,1 };
L[i * 2] = { lx,rx,ry,-1 };
}
sort(L + 1, L + 1 + 2 * n);
sort(nums + 1, nums + 1 + cnt);
cnt = unique(nums + 1, nums + 1 + cnt) - nums - 1;
ans = 0;
for (int i = 1; i <= 2 * n - 1; i++) {
int lid = lower_bound(nums + 1, nums + 1 + cnt, L[i].l) - nums;
int rid = lower_bound(nums + 1, nums + 1 + cnt, L[i].r) - nums;
//printf("[%d,%d] : %d\n", lid, rid, L[i].tag);
updt(lid, rid, L[i].tag);
ans = max(ans, mx[1]);
}
printf("%d\n", ans);
}
}
其实跟扫描线没什么关系,就是一个区间修改,区间求最大值的问题