POJ_2482 Stars in Your Window 扫描线 + 线段树

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

题意:

给你一个二维坐标系,和其中的一些点,这些点每个都有一个自己的value,要求用一个W*H的矩形框 框住尽可能多的点,并且使得被包括的点的values和最大。

思路:

和黑书上的一道例题类似,我们可以先将所有的点分成两个点,一个是原来的点(x,y,v) ,再加一个点(x+W,y,-v),然后将所有的点按照X排序,(这样做的好处是当我们设置一个扫描线从左到右扫描的时候,在扫描线控制的区域(也就是合法的矩形区域内)不能再控制到一个点的时候(也就是这个点的值不能再算在后面的计算中的时候)我们可以及时地将改点“剔除”),然后从左到右设置一个扫描线,每次扫描到一个点,就在Y轴上的y处的值加上一个values, 在y+H处加上一个-values(这样做的好处是控制Y轴方向上的坐标在H范围内,原来和上面所说的控制X轴方向上的范围是一样的)。 最后线段树的节点需要维护一个sum 和max ,分别表示区间内的和,和区间的前缀和。 

代码:

#include<stdio.h>
#include<string.h>
#include<algorithm>
typedef long long LL ;
LL  N , W , H ;
const int MAXN = 20050 ;

struct point{
    LL x , y , s ;
    point(){}
    point(LL a, LL b ,LL c)
    :x(a),y(b),s(c){}
    bool operator< (const point& cmp ) const {
        if(x == cmp.x)  return s < cmp.s ;      //这里需要注意
        return x < cmp.x ;
    }
}p[MAXN] ;

LL Y[MAXN] ;
LL sum[MAXN<<2] , max[MAXN<<2] ;

LL find(LL l, LL r, LL val ){
    while( l<r ){
        LL mid = (l + r) >> 1 ;
        if( Y[mid] < val )  l = mid + 1;
        else        r = mid ;
    }
    return l ;
}

void up(LL l ,LL r, LL idx){
    LL ls = idx<<1 , rs = idx<<1|1 ;
    sum[idx] = sum[ls] + sum[rs] ;

    max[idx] = max[ls] ;
    if( max[idx] < sum[ls] + max[rs] )
        max[idx] = sum[ls] + max[rs] ;
}

void update(LL l ,LL r, LL idx, LL pos , LL val){
    if(l == r){
        sum[idx] += val ;
        max[idx] += val ;
        return ;
    }
    LL mid = (l + r) >> 1 ;
    LL ls = idx<<1 ,rs = idx<<1|1 ;
    if( pos<= mid ) update(l ,mid ,ls ,pos , val );
    else        update(mid+1, r, rs, pos,  val );
    up(l ,r,idx);
}

void solve(LL m , LL n){
    memset(sum , 0 ,sizeof(sum)) ;
    memset(max, 0 , sizeof(max)) ;
    LL _max = 0 ;
    for(LL i=0;i<m;i++){
        LL s = find(0 , n , p[i].y ) ;
        LL e = find(0 , n , p[i].y+H) ;
        if( _max < max[1] ) _max = max[1] ;
        update(0 , MAXN , 1 , s , p[i].s ) ;
        update(0 , MAXN , 1 , e , -p[i].s ) ;
    }
    printf("%lld\n",_max);
}

int main(){
    LL x, y ,v ;
    while( scanf("%lld%lld%lld",&N,&W,&H) == 3){
        for(LL i=0;i<N;i++){
            scanf("%lld%lld%lld",&x,&y,&v);
            p[i<<1] = point(x , y , v);
            p[i<<1|1] = point(x+W , y , -v );
            Y[i<<1] = y ; Y[i<<1|1] = y + H  ;
        }
        LL m = N<<1 ;
        std::sort(Y , Y+m);
        std::sort(p , p+m);
        LL n = 1 ;
        for(LL i=1;i<m;i++){
            if( Y[i]!=Y[i-1] )  Y[n++] = Y[i] ;
        }
        n-- ;
        solve( m , n );
    }
    return 0 ;
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值