hdu 5091 Beam Cannon(线段树)

给出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;
}


你可能感兴趣的:(线段树,扫描线)