POJ 2482 扫描线法 + 线段树

题意

传送门 POJ 2482 Stars in Your Window

题解

坐标范围过大,考虑矩形的左下角。考虑到不统计边界的星星,此时能围住每一颗星星 ( x , y ) (x,y) (x,y) 的矩形的左下角范围也是个矩形区域 ( x − W + 1 , y − H + 1 ) (x-W+1,y-H+1) (xW+1,yH+1),实现上在坐标上使用左闭右开区间,将 x x x 范围平移为 [ x − W , x ) [x-W,x) [xW,x),将 y y y 范围平移为 [ y − H , y ) [y-H,y) [yH,y)。于是问题转化为平面上有若干矩形区域,求在哪个坐标处重叠区域的权值和最大。

使用扫描线法, ( x − W , y − H , y , c ) , ( x , y − H , y , − c ) (x-W,y-H,y,c),(x,y-H,y,-c) (xW,yH,y,c),(x,yH,y,c) 两个四元组保存边界信息,对 y y y 方向离散化处理,顺序扫描 x x x 轴,使用线段树维护 y y y 方向的最大值,当更新完一条扫描线后及时更新答案。

#include <algorithm>
#include <cstdio>
#include <cstring>
using namespace std;
const int maxn = 10005, sg_size = 1 << 16;
struct P
{
    int x, y1, y2, d;
    bool operator<(const P &b) const { return x < b.x; }
} A[maxn << 1];
struct P2
{
#define mx(x) tree[x].mx
#define ad(x) tree[x].ad
    int mx, ad;
} tree[sg_size];
int N, W, H, ny, sy[maxn << 1];

inline int cp(int y) { return lower_bound(sy, sy + ny, y) - sy; }

void init(int k, int l, int r)
{
    mx(k) = ad(k) = 0;
    if (r - l == 1)
        return;
    int lc = (k << 1) + 1, rc = (k << 1) + 2, m = (l + r) >> 1;
    init(lc, l, m), init(rc, m, r);
}

inline void pushdown(int k, int lc, int rc)
{
    if (ad(k))
    {
        int &x = ad(k);
        mx(lc) += x, ad(lc) += x, mx(rc) += x, ad(rc) += x;
        x = 0;
    }
}

void change(int a, int b, int x, int k, int l, int r)
{
    if (r <= a || b <= l)
        return;
    if (a <= l && r <= b)
    {
        ad(k) += x, mx(k) += x;
        return;
    }
    int lc = (k << 1) + 1, rc = (k << 1) + 2, m = (l + r) >> 1;
    pushdown(k, lc, rc);
    change(a, b, x, lc, l, m), change(a, b, x, rc, m, r);
    mx(k) = max(mx(lc), mx(rc));
}

int main()
{
    while (~scanf("%d%d%d", &N, &W, &H))
    {
        for (int i = 0, k = 0; i < N; ++i)
        {
            int x, y, c;
            scanf("%d%d%d", &x, &y, &c);
            A[i].d = c, A[N + i].d = -c, A[i].x = x - W, A[N + i].x = x;
            sy[k++] = A[i].y1 = A[N + i].y1 = y - H, sy[k++] = A[i].y2 = A[N + i].y2 = y;
        }
        ny = (N <<= 1);
        sort(sy, sy + ny);
        ny = unique(sy, sy + ny) - sy;
        sort(A, A + N);
        init(0, 0, ny - 1);
        int res = 0;
        for (int i = 0; i + 1 < N; ++i)
        {
            change(cp(A[i].y1), cp(A[i].y2), A[i].d, 0, 0, ny - 1);
            if (A[i].x != A[i + 1].x)
                res = max(res, tree[0].mx);
        }
        printf("%d\n", res);
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值