给出n个点和一个矩形的长和宽, 问这个矩形最多能覆盖多少个点。
矩形放的最优方案一定存在一种是左边界或者右边界上有点,假设是左边界上有点, 就可以枚举左边界上的是哪个点, 也就是从左向右扫, 假设扫到了第i个点, 那么在第i个点右边并且x坐标距离小于w的点j, 如果矩形的上边界在a[j].y 和a[j].y + h之间的话, 那么矩形就可以覆盖这个点, 所以每个点都是对a[j].y 和a[j].y + h这段区间加1, 然后答案就是整个区间的最大值, 用线段树维护就可以了。。
#include <iostream> #include <cstdio> #include <cstring> #include <queue> #include <algorithm> using namespace std; #define mnx 10020 #define inf 0x3f3f3f3f #define ls (i << 1) #define rs (ls | 1) #define md ((ll + rr) >> 1) int n, w, h; struct point { int x, y; bool operator < (const point &b) const { if(x != b.x) return x < b.x; return y < b.y; } }a[mnx]; int san[mnx * 2], cnt; int haxi(int x) { return lower_bound(san + 1, san + cnt + 1, x) - san; } int mx[mnx * 8], add[mnx * 8]; void build(int ll, int rr, int i) { mx[i] = add[i] = 0; if(ll == rr) return; build(ll, md, ls), build(md + 1, rr, rs); } void down(int i) { if(add[i]) { mx[ls] += add[i], mx[rs] += add[i]; add[ls] += add[i], add[rs] += add[i]; add[i] = 0; } } void update(int l, int r, int v, int ll, int rr, int i) { if(ll == l && rr == r) { mx[i] += v; add[i] += v; return; } down(i); if(r <= md) update(l, r, v, ll, md, ls); else if(l > md) update(l, r, v, md + 1, rr, rs); else update(l, md, v, ll, md, ls), update(md + 1, r, v, md + 1, rr, rs); mx[i] = max(mx[ls], mx[rs]); } int main() { while(scanf("%d%d%d", &n, &w, &h) && n > 0) { cnt = 0; for(int i = 1; i <= n; ++i) { scanf("%d%d", &a[i].x, &a[i].y); san[++cnt] = a[i].y; san[++cnt] = a[i].y + h; } sort(a + 1, a + n + 1); sort(san + 1, san + cnt + 1); cnt = unique(san + 1, san + cnt + 1) - san - 1; int j = 1; int ans = 0; build(1, cnt, 1); for(int i = 1; i <= n; ++i) { while(j <= n && a[j].x <= a[i].x + w) { int u = a[j].y; int v = a[j].y + h; u = haxi(u), v = haxi(v); update(u, v, 1, 1, cnt, 1); ++j; } ans = max(ans, mx[1]); int u = a[i].y; int v = a[i].y + h; u = haxi(u), v = haxi(v); update(u, v, -1, 1, cnt, 1); } printf("%d\n", ans); } return 0; }