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

 

 

posted on 2012-07-13 14:58  夜->  阅读(173)  评论(0编辑  收藏  举报