poj 2482 Stars in Your Window (线段树:区间更新)

题目链接:http://poj.org/problem?id=2482

读完题干不免有些心酸(??????)

题意:有n个星星(星星i的坐标为xi, yi,亮度为ci),给你一个W*H的矩形,让你求得矩形能覆盖的星星的亮度和最大为多少

思路:矩形大小是固定的,所以可以换个方向思考,把矩形看成一个点(坐标为矩形中心),每个星星的影响区间范围为W*H的矩形(星星原来的坐标为矩形中心),该区间的亮度增加c。该问题就变成了求哪个点的亮度最大。坐标范围太大,直接暴力枚举不可能,所以需要预先进行离散化。在纵向上建立一个线段树,然后枚举横坐标,每次在线段树上将需要更新的纵向坐标区间进行更新,然后进行查询。

#include <iostream>
#include <cstring>
#include <algorithm>
#define maxn 10010
#define inf 1000000000
#define LL(x) x<<1
#define RR(x) x<<1|1
using namespace std;

typedef long long LL;

//variable define

struct line
{
    int x, y1, y2, light;
};

struct tree
{
    int l, r;
    int add;
    LL ma;
};

tree node[maxn * 8];
LL W, H, starx[maxn], stary[maxn], xx[maxn*2], yy[maxn*2];
int light[maxn], n;
line li[maxn * 4];

//function define

void push_down(int x);

void push_up(int x);

void build_tree(int left, int right, int x);

LL query(int left, int right, int x);

void update_add(int left, int right, int x, LL val);

bool line_compare( line l1, line l2);

int main(void)
{
    while (scanf("%d %lld %lld", &n, &W, &H) != EOF)
    {
        for (int i = 0; i < n; ++i)
        {
            scanf("%lld %lld %d", &starx[i], &stary[i], &light[i]);
            starx[i] *= 2;
            stary[i] *= 2;
        }
        for (int i = 0; i < n; ++i)
        {
            xx[i*2] = starx[i] - W;
            xx[i*2 + 1] = starx[i] + W;
            yy[i*2] = stary[i] - H;
            yy[i*2 + 1] = stary[i] + H - 1;
        }
        sort( xx, xx + 2*n);
        sort( yy, yy + 2*n);
        for (int i = 0; i < n; ++i)
        {
            int x, y1, y2;
            x = (int)(lower_bound( xx, xx + 2*n, starx[i] - W) - xx);
            y1 = (int)(lower_bound( yy, yy + 2*n, stary[i] - H) - yy);
            y2 = (int)(lower_bound( yy, yy + 2*n, stary[i] + H - 1) - yy);
            li[i*2].x = x;
            li[i*2].y1 = y1;
            li[i*2].y2 = y2;
            li[i*2].light = light[i];

            x = (int)(lower_bound( xx, xx + 2*n, starx[i] + W) - xx);
            li[i*2 + 1].x = x;
            li[i*2 + 1].y1 = y1;
            li[i*2 + 1].y2 = y2;
            li[i*2 + 1].light = -1*light[i];
        }
        build_tree( 1, 2*n, 1);
        LL ans = 0;
        sort( li, li + 2*n, line_compare);
        for (int i = 0; i < 2*n; ++i)
        {
            update_add( li[i].y1 + 1, li[i].y2 + 1, 1, li[i].light);
            ans = max( ans, query( li[i].y1 + 1, li[i].y2 + 1, 1));
        }
        printf("%lld\n", ans);
    }
    return 0;
}

void build_tree(int left, int right, int x)
{
    node[x].l = left;
    node[x].r = right;
    node[x].add = node[x].ma = 0;

    if (left == right)
        return;

    int lx = LL(x);
    int rx = RR(x);
    int mid = left + (right - left)/2;
    build_tree(left, mid, lx);
    build_tree(mid + 1, right, rx);
    push_up(x);
}

void push_up(int x)
{
    if (node[x].l >= node[x].r)
        return;

    int lx = LL(x);
    int rx = RR(x);
    node[x].ma = max( node[lx].ma, node[rx].ma);
}

void push_down(int x)
{
    if (node[x].l >= node[x].r)
        return;
    int lx = LL(x);
    int rx = RR(x);

    if (node[x].add != 0)
    {
        node[lx].add += node[x].add;
        node[rx].add += node[x].add;
        node[lx].ma += node[x].add;
        node[rx].ma += node[x].add;
    }
}

void update_add(int left, int right, int x, LL val)
{
    if (node[x].l == left && node[x].r == right)
    {
        node[x].add += val;
        node[x].ma += val;
        return;
    }
    push_down( x);
    node[x].add = 0;
    int lx = LL(x);
    int rx = RR(x);
    int mid = node[x].l + (node[x].r - node[x].l)/2;

    if (right <= mid)
        update_add(left, right, lx, val);
    else if (left > mid)
        update_add(left, right, rx, val);
    else
    {
        update_add(left, mid, lx, val);
        update_add(mid + 1, right, rx, val);
    }
    push_up(x);
}

LL query(int left, int right, int x)
{
    if (node[x].l == left && node[x].r == right)
    {
        return node[x].ma;
    }

    push_down(x);
    node[x].add = 0;

    int mid = node[x].l + (node[x].r - node[x].l)/2;
    int lx = LL(x);
    int rx = RR(x);
    LL result;
    if (right <= mid)
        result = query(left, right, lx);
    else if (left > mid)
        result = query(left, right, rx);
    else
        result = max( query(left, mid, lx), query(mid + 1, right, rx));
    push_up(x);
    return result;
}

bool line_compare(line l1, line l2)
{
    if (l1.x != l2.x)
        return l1.x < l2.x;
    return l1.light < l2.light;
}
时间: 2024-08-11 07:48:48

poj 2482 Stars in Your Window (线段树:区间更新)的相关文章

POJ 2482 Stars in Your Window 线段树+离散化+扫描线

题面据说很美- 每个星星可以根据在窗口的左下角和右上角两个位置建立两条扫描线,之后就是简单的区间增减和求最大值操作了. 注意要处理在边界上的星星是不算的情况,其实只要把左右边界分别增减一个eps即可. #include <cstdio> #include <cstring> #include <iostream> #include <map> #include <set> #include <vector> #include <

POJ 2482 Stars in Your Window 线段树扫描线

Stars in Your Window Description Fleeting time does not blur my memory of you. Can it really be 4 years since I first saw you? I still remember, vividly, on the beautiful Zhuhai Campus, 4 years ago, from the moment I saw you smile, as you were walkin

POJ 2482 stars in your window(线段树 , 扫描线)

题目大意: 给你10000以内的星星的坐标和亮度,让你用一个W × H 的矩形去围住一个区域,使得区域内星星的亮度最大,矩形边缘上的星星不算. 解题思路: 对于每一个星星 建立一个(x, y , y + h , c) 的扫描线 和一个(x + w , y , y + h , - c)的扫描线,将问题转化成求区间最大值.几个需要注意的地方:矩形边缘上的需要处理一下,将每个叶节点设为长度为1的线段.另外此题如果用long long wa掉的话可以改为unsigned. #include <iostr

POJ 2777 &amp;&amp; ZOJ 1610 &amp;&amp;HDU 1698 --线段树--区间更新

直接将这3题 放一起了  今天在做线段树的东西 这3个都是区间更新的 查询方式互相不同 反正都可以放到一起吧 直接先上链接了 touch me touch me touch me 关于涉及到区间的修改 -- 区间更新的话 分为 增减 或者 修改 主要就是个 laze 标记 就是延迟更新 对于区间更新的写法 一般是有2种 其一 仔细划分到每个细小的区间    另一 粗略划分 反正 ==我的代码里会给出2种写法 看自己喜好 hdu 1 //线段树 成段更新 ---> 替换 根结点的查询 2 3 #i

POJ 2482 Stars in Your Window(线段树)

POJ 2482 Stars in Your Window 题目链接 题意:给定一些星星,每个星星都有一个亮度,现在要用w * h的矩形去框星星,问最大能框的亮度是多少 思路:转化为扫描线的问题,每个星星转化为一个矩形,那么等于求矩形相交区域值最大的区域,利用线段树去维护即可 代码: #include <cstdio> #include <cstring> #include <algorithm> using namespace std; typedef long lo

poj 2482 Stars in Your Window(扫描线)

题目链接:poj 2482 Stars in Your Window 题目大意:平面上有N个星星,问一个W?H的矩形最多能括进多少个星星. 解题思路:扫描线的变形.只要以每个点为左上角,建立矩形,这个矩形即为框框左下角放的位置可以括到该点,那么N个星星就有N个矩形,扫描线处理哪些位置覆盖次数最多. #include <cstdio> #include <cstring> #include <vector> #include <algorithm> using

POJ 2528 Mayor&#39;s posters (线段树区间更新+离散化)

题目链接:http://poj.org/problem?id=2528 给你n块木板,每块木板有起始和终点,按顺序放置,问最终能看到几块木板. 很明显的线段树区间更新问题,每次放置木板就更新区间里的值.由于l和r范围比较大,内存就不够了,所以就用离散化的技巧 比如将1 4化为1 2,范围缩小,但是不影响答案. 写了这题之后对区间更新的理解有点加深了,重点在覆盖的理解(更新左右两个孩子节点,然后值清空),还是要多做做题目. 1 #include <iostream> 2 #include <

POJ 2777 Count Color (线段树区间更新加查询)

Description Chosen Problem Solving and Program design as an optional course, you are required to solve all kinds of problems. Here, we get a new problem. There is a very long board with length L centimeter, L is a positive integer, so we can evenly d

POJ 3468 A Simple Problem with Integers(线段树区间更新)

题目地址:POJ 3468 打了个篮球回来果然神经有点冲动..无脑的狂交了8次WA..居然是更新的时候把r-l写成了l-r... 这题就是区间更新裸题.区间更新就是加一个lazy标记,延迟标记,只有向下查询的时候才将lazy标记向下更新.其他的均按线段树的来就行. 代码如下: #include <iostream> #include <cstdio> #include <cstring> #include <math.h> #include <stac

线段树 + 区间更新 + 模板 ---- poj 3468

A Simple Problem with Integers Time Limit: 5000MS   Memory Limit: 131072K Total Submissions: 59798   Accepted: 18237 Case Time Limit: 2000MS Description You have N integers, A1, A2, ... , AN. You need to deal with two kinds of operations. One type of