Poj 2482 Stars in Your Window(用W*H的矩形去围住一个区域,使得这个区域内的星星的亮度最大)

传送门:Poj 2482 Stars in Your Window


题意:给你10000以内的星星的坐标和星星的亮度(即分别为x,y,c),要求用W*H的矩形去围住一个区域,使得这个区域内的星星的亮度最大,并且要求矩形边框上的星星不计入内。矩形可以平移,但不能旋转。


思路:
对x轴维护一个队列,使得任意两个点的x轴的距离小于W
对于y轴,把每个点拆分成y和y+H,[y,INF]加上c,[y+H,INF]加上-c
维护一个前缀的最大值


#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
using namespace std;
const int N=1e5;

struct Point{
    long long x,y;
    int c;
}a[N];
long long y[N];
int addv[N],maxv[N];

bool cmp(Point u,Point v){
    if(u.x!=v.x)
        return u.x<v.x;
    return u.y<v.y;
}

int L,R,num;

void pushup(int rt){
    maxv[rt]=max(maxv[rt<<1],maxv[rt<<1|1]);
}

#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1

void pushdown(int rt){
    if(addv[rt]){
        maxv[rt<<1]+=addv[rt];
        maxv[rt<<1|1]+=addv[rt];
        addv[rt<<1]+=addv[rt];
        addv[rt<<1|1]+=addv[rt];
        addv[rt]=0;
    }
}

void update(int l,int r,int rt){
    if(L<=l&&R>=r){
        addv[rt]+=num;
        maxv[rt]+=num;
        return ;
    }
    pushdown(rt);
    int m=l+r>>1;
    if(L<=m)    update(lson);
    if(R>m)     update(rson);
    pushup(rt);
}

int main(){
    int n,W,H;
    while(scanf("%d%d%d",&n,&W,&H)!=EOF){
        int tot_x=0,tot_y=0,tot=0;
        for(int i=1;i<=n;++i){
            scanf("%lld%lld%d",&a[i].x,&a[i].y,&a[i].c);
            y[++tot_y]=a[i].y,y[++tot_y]=a[i].y+H;
        }
        sort(a+1,a+n+1,cmp);
        sort(y+1,y+tot_y+1);
        tot_y=unique(y+1,y+tot_y+1)-y-1;
        memset(addv,0,sizeof(addv));
        memset(maxv,0,sizeof(maxv));
        int ans=0,st=1;
        for(int i=1;i<=n;++i){
            ans=max(ans,maxv[1]);
            while(st<i&&a[i].x-a[st].x>=W){
                int l=lower_bound(y+1,y+tot_y+1,a[st].y)-y,r=lower_bound(y+1,y+tot_y+1,a[st].y+H)-y;
                L=l,R=tot_y,num=-a[st].c;
                update(1,tot_y,1);
                L=r,R=tot_y,num=a[st].c;
                update(1,tot_y,1);
                ++st;
            }
            int l=lower_bound(y+1,y+tot_y+1,a[i].y)-y,r=lower_bound(y+1,y+tot_y+1,a[i].y+H)-y;
            L=l,R=tot_y,num=a[i].c;
            update(1,tot_y,1);
            L=r,R=tot_y,num=-a[i].c;
            update(1,tot_y,1);
            //printf("PPPPPP\n");
        }
        ans=max(ans,maxv[1]);
        printf("%d\n",ans);
    }
    return 0;
}

思路二:如果c可能为负数,对于每一个星星,分别建立线(x,y,y+H,c)和(x+W,y,y+H,-c)。这样处理的原因是我们就可以把问题转化成求线段树里某一段内的最大值,即区间查询。矩形边框上的星星不计的处理方法是:1.对于x轴方面的处理是在排序的时候,优先-c的边,因为如果优先+c的边,那么就是将边框上的星星计入了。2.对于y轴方面的,我的处理方法是将线段树的叶子结点处理成长度为1的区间(转自http://blog.csdn.net/shiqi_614/article/details/7819232)

例如数据:
4 4 3
0 1 -100
0 2 -100
1 2 1
3 0 1

#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
using namespace std;
const int N=1e5;

struct Point{
    long long x,y1,y2;
    int c;
}a[N*2];
long long y[N];
int addv[N],maxv[N];

bool cmp(const Point& u,const Point& v){
    if(u.x!=v.x)
        return u.x<v.x;
    return u.c<v.c;
}

int L,R,num;

void pushup(int rt){
    maxv[rt]=max(maxv[rt<<1],maxv[rt<<1|1]);
}

#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1

void pushdown(int rt){
    if(addv[rt]){
        maxv[rt<<1]+=addv[rt];
        maxv[rt<<1|1]+=addv[rt];
        addv[rt<<1]+=addv[rt];
        addv[rt<<1|1]+=addv[rt];
        addv[rt]=0;
    }
}

void update(int l,int r,int rt){
    if(L<=l&&R>=r){
        addv[rt]+=num;
        maxv[rt]+=num;
        return ;
    }
    pushdown(rt);
    int m=l+r>>1;
    if(L<=m)    update(lson);
    if(R>m)     update(rson);
    pushup(rt);
}

int main(){
    int n,W,H;
    while(scanf("%d%d%d",&n,&W,&H)!=EOF){
        int tot_y=0,tot=0,c;
        long long x,y1;
        for(int i=1;i<=n;++i){
            scanf("%lld%lld%d",&x,&y1,&c);
            a[i*2-1]=(Point){x,y1,y1+H-1,c};
            a[i*2]=(Point){x+W,y1,y1+H-1,-c};
            y[++tot_y]=y1,y[++tot_y]=y1+H-1;
        }
        sort(a+1,a+2*n+1,cmp);
        sort(y+1,y+tot_y+1);
        tot_y=unique(y+1,y+tot_y+1)-y-1;
        memset(addv,0,sizeof(addv));
        memset(maxv,0,sizeof(maxv));
        int ans=-100000000,st=1;
        for(int i=1;i<=2*n;i++){
            L=lower_bound(y+1,y+tot_y+1,a[i].y1)-y,R=lower_bound(y+1,y+tot_y+1,a[i].y2)-y;
            num=a[i].c;
            update(1,tot_y,1);
            ans=max(ans,maxv[1]);
        }
        printf("%d\n",ans);
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值