poj2482 Stars in Your Window(成段更新+扫描线)


http://poj.org/problem?id=2482

题意:给你n个星星的x,y,val,求用一个长w宽h圈住的最大亮度的值(还有这题前缀长的不忍直视啊)。


思路:这题关键点在于对问题的转化,按照最笨的暴力枚举只会超时。这里我们设刚开始给的框代号X,以ABC点为中心临时做出来的框为代号ABC...。我们知道一个矩形的中心点可以代表它的位置,那么以A为中心,作w、h的矩形A,此矩形的范围表示框X的中心点在这个范围内即可圈住该点。设想如果有两个矩形A和B有交集,那么交集部分表示既可以圈住A点,也可以圈住B点,所以任意矩形的交集表示可以圈住任意的点。那么这里求框内最大亮度就转化成了求覆盖面积的最大值。

这样的话就是成段更新求最值+扫描线的思路了。那么点如何代表矩形呢?按我们上面的思路是按照点为中心做矩形,这里直接将横坐标平移w个单位,所有点都平移效果不会变。离散纵坐标值,扫描线从左往右扫描。还要注意这里做出的矩形是有权值的,一条线段映射到线段树里就是成段更新,lazy也可以用上。


#include <stdio.h>
#include <algorithm>
#include <stdlib.h>
#include <string.h>
#include <iostream>

using namespace std;

typedef long long LL;

const int N = 100010;
const int INF = 1e8;

struct line
{
    __int64 l, r;
    __int64 sum;
    __int64 add;
}tree[8*N];

struct node
{
    __int64 w, h;
    __int64 val;
    bool operator < (const struct node & tmp) const
    {
        if(w == tmp.w)
            return val < tmp.val;
        return w < tmp.w;
    }
}point[8*N];

__int64 y[N*8];

void build(__int64 i, __int64 l, __int64 r)
{
    tree[i].l = l;
    tree[i].r = r;
    tree[i].add = 0;
    tree[i].sum = 0;
    if(l == r)
    {
        return;
    }
    __int64 mid = (l+r) >> 1;
    build(i*2, l, mid);
    build(i*2+1, mid+1, r);
}

__int64 binsearch(__int64 key, __int64 k)
{
    __int64 high = k;
    __int64 low = 1;
    while(high >= low)
    {
        __int64 mid = (high+low) >> 1;
        if(y[mid] == key)
        {
            return mid;
        }
        else if(y[mid] < key)
        {
            low = mid+1;
        }
        else high = mid-1;
    }
    return -1;
}


void update(__int64 i, __int64 l, __int64 r, __int64 val)
{
    if(tree[i].l == l && tree[i].r == r)
    {
        tree[i].add += val;
        tree[i].sum += val;
        return;
    }
    if(tree[i].add)
    {
        tree[i*2].add += tree[i].add;
        tree[i*2+1].add += tree[i].add;
        tree[i*2].sum += tree[i].add;
        tree[i*2+1].sum += tree[i].add;
        tree[i].add = 0;
    }
    __int64 mid = (tree[i].l+tree[i].r) >> 1;
    if(mid >= r)
        update(i*2, l, r, val);
    else if(mid < l)
        update(i*2+1, l, r, val);
    else
    {
        update(i*2, l, mid, val);
        update(i*2+1, mid+1, r, val);
    }
    tree[i].sum = max(tree[i*2].sum, tree[i*2+1].sum);
}

int main()
{
  //  freopen("in.txt", "r", stdin);
    __int64 n, w, h;
    while(~scanf("%I64d%I64d%I64d", &n, &w, &h))
    {
        for(__int64 i = 1; i <= n; i++)
        {
            scanf("%I64d%I64d%I64d", &point[i].w, &point[i].h, &point[i].val);
            y[i] = point[i].h;
            y[i+n] = point[i].h+h;
            point[i+n].w = point[i].w+w;
            point[i+n].h = point[i].h;
            point[i+n].val = -point[i].val;
        }
        sort(point+1, point+1+n*2);
        sort(y+1, y+1+n*2);
        __int64 k = 1;
        for(__int64 i = 2; i <= n*2; i++)
        {
            if(y[i-1] != y[i])
            {
                y[++k] = y[i];
            }
        }
        build(1, 1, k);
        __int64 ans = 0;
        for(__int64 i = 1; i <= n*2; i++)
        {
            __int64 l = binsearch(point[i].h, k);
            __int64 r = binsearch(point[i].h+h, k)-1;
            if(l > r) swap(l, r);
          //  printf("%I64d %I64d\n", l, r);
            update(1, l, r, point[i].val);
            ans = max(ans, tree[1].sum);
        }
        printf("%I64d\n", ans);
    }
    return 0;
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值