poj 2482 Stars in Your Window

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

黑书的102~104有个十分类似的题,解法一样 推荐

题目大意:

刚开始的情书 ,十分的不错。

给你个矩形去框星星 矩形能移不能转,边框上的星星不算,星星都是有亮度值的

问可以得到的最大亮度值和

思路:

由于都是整数,比如说边框左边有星星 右边也有星星 只有左右移动一下就可以多框

一些星星,所以我们默认 边框星星 取左不取右,取下不取上

我们对y坐标排序,根据y建二叉树 左子树一定小于根节点 右子树一定大于根节点

对x排序,我们用两个扫描线,使它们两者之间的星星x距离不超过w

然后对其求最大矩形内亮度和。

我们可以把一个点拆成两个 原来的点是x ,y,value再多加一个点 x,y+h,-value

这样的话 两个扫描线之间的星星求矩形内点亮度和,变成了,用一个扫描线向上扫,求扫过部分的

所用点的两度和。

至于点的更新 和答案的更新 见代码及其注释:

#include<iostream>

#include<cstdio>

#include<cstring>

#include<string>

#include<cmath>

#include<queue>

#include<algorithm>



using namespace std;



const int N=10010;

struct node

{

    int I;//在完全二叉树里的位置

    int x;

    unsigned int y;//y加h后会超过2^31

    int value;

}mem[N*4];

struct tree

{

    int value;

    int max;

    int sum;

}btree[N*8];

bool cmpx(node a,node b)

{

    return a.x<b.x;

}

bool cmpy(node a,node b)

{

    if(a.y==b.y)//要把负的value排在前面

    return a.value<b.value;

    return a.y<b.y;

}

void build(int l,int r,int w)

{

    int k=(l+r+1)>>1;//区间内的根节点

    mem[k].I=w;//记录在完全二叉树里的位置

    if(l<k)

    {

        build(l,k-1,2*w);

    }

    if(k<r)

    {

        build(k+1,r,2*w+1);

    }

}

void update(int x)

{

    btree[x].sum=btree[x*2].sum+btree[x*2+1].sum+btree[x].value;//sum需要相加

    btree[x].max=max(max(btree[x*2].max,0),//max需要用到DP的思想

                    max(btree[x*2].sum+btree[x].value,btree[x*2].sum+btree[x].value+btree[x*2+1].max));

    if(x!=1)//不是总根节点 继续更新

    {

        update(x/2);

    }

}

int main()

{

    int n,w,h;

    while(scanf("%d %d %d",&n,&w,&h)!=EOF)

    {

        for(int i=1;i<=n;++i)

        {

            scanf("%d %d %d",&mem[i].x,&mem[i].y,&mem[i].value);

        }

        for(int i=n+1;i<=2*n;++i)//一个点拆成两个点

        {

            mem[i].x=mem[i-n].x;

            mem[i].y=mem[i-n].y+h;

            mem[i].value=-mem[i-n].value;

        }

        for(int i=0;i<=4*n+1;++i)//初始化 4*n+1 中的+1很重要

        {

            btree[i].max=0;

            btree[i].value=0;

            btree[i].sum=0;

        }

        sort(mem+1,mem+2*n+1,cmpy);//按y排序

        build(1,2*n,1);//建树 实际上是找好对于的点

        sort(mem+1,mem+2*n+1,cmpx);//按x排序

        int L,R;

        L=R=1;

        int ans=0;

        while(R<=2*n)

        {

            while(R<=2*n&&mem[R].x-mem[L].x<w)//加点

            {

                btree[mem[R].I].value=mem[R].value;

                update(mem[R].I);

                ++R;

            }

            ans=max(ans,btree[1].max);//加点后求最大值

            while(R<=2*n&&mem[R].x-mem[L].x>=w)//去点

            {

                btree[mem[L].I].value=0;

                update(mem[L].I);

                ++L;

            }

        }

        printf("%d\n",ans);

    }

    return 0;

}

 

 

你可能感兴趣的:(window)