poj 2482 Stars in Your Window(线段树,扫描线)


poj 2482 Stars in Your Window


题意,移动一个固定大小的矩形,使矩形中的星星亮度之和最大(边框上的不算),输出该值


这个题把可移动的矩形转换为扫描线的方式来做非常巧妙,以每颗星星(亮度为val)为左下角建立一个矩形(向Y轴映射),左竖边的值就为val,右竖边的值为-val,试想一下如果有两个矩形有重叠部分的话那么这两个矩形所代表的两颗星星必定能被一个矩形圈在一起,这样我们就能利用扫描线求出重叠部分的值。

离散化后进行扫描线操作,每个节点Lazy维护一个最大值maxval,这样每一次插入一条线在根节点就保存得有当前整棵树最大值,即当前矩形能圈住的最大值。

需要注意的:

因为边框上的星星不算在矩形内,所以排序的时候在x坐标相同的情况下,val值小的应在前面

我的写法中可能有中间结果超int,导致出现负数,然后一直RE啊RE(吐血)、、、本来可以1A的,一怒之下全改成long long、、、


#include<cstdio>
#include<cstring>
#include<map>
#include<algorithm>
#include<iostream>
using namespace std;
#define ll long long
#define MAXN 200100
#define lch p<<1
#define rch p<<1|1
struct ele
{
    ll x,yd,yu;
    ll val;
    bool operator < (const ele &a) const
    {
        if(x==a.x)
            return val<a.val;
        else return x<a.x;
    }
}seg[MAXN*4];
struct node
{
    ll l,r;
    ll val;
    ll maxval;
}t[MAXN*8];
ll max(ll a,ll b) {return a>b?a:b;}
void construct(ll l,ll r,ll p)
{
    t[p].l=l,t[p].r=r;
    t[p].val=t[p].maxval=0;
    if(r-l<=1) return ;
    ll m=(l+r)>>1;
    construct(l,m,lch);
    construct(m,r,rch);
}
void pushdown(ll p)
{
    t[lch].val+=t[p].val;
    t[rch].val+=t[p].val;
    t[lch].maxval+=t[p].val;
    t[rch].maxval+=t[p].val;
    t[p].val=0;
}
void modify(ll l,ll r,ll val,ll p)
{
    if(t[p].l==l&&t[p].r==r)
    {
        t[p].maxval+=val;
        t[p].val+=val;
        return ;
    }
    
    if(t[p].val) pushdown(p);
    
    ll m=(t[p].l+t[p].r)>>1;
    if(r<=m) modify(l,r,val,lch);
    else if(l>=m) modify(l,r,val,rch);
    else modify(l,m,val,lch),modify(m,r,val,rch);
    
    t[p].maxval=max(t[lch].maxval,t[rch].maxval);
}
ll yy[MAXN*4];
map<ll,ll> rec;
int main()
{
    //freopen("in.txt","r",stdin);
    //freopen("out.txt","w",stdout);
    ll i,n,w,h,x,y,val;
    while(scanf("%lld%lld%lld",&n,&w,&h)!=EOF)
    {
        for(i=0;i<(n<<1);i+=2)
        {
            scanf("%lld%lld%lld",&x,&y,&val);
            seg[i].x=x,seg[i].yd=y,seg[i].yu=y+h,seg[i].val=val;
            seg[i+1].x=x+w,seg[i+1].yd=y,seg[i+1].yu=y+h,seg[i+1].val=-val;
            yy[i]=y;
            yy[i+1]=y+h;
        }
        sort(seg,seg+(n<<1));
        sort(yy,yy+(n<<1));
        ll up=(int)(unique(yy,yy+(n<<1))-yy);
        rec.clear();
        for(i=0;i<up;i++)
            rec[yy[i]]=i;//printf("%d\n",yy[i]);
        ll ans=0;
        construct(0,up,1);
        for(i=0;i<(n<<1);i++)
        {
            modify(rec[seg[i].yd],rec[seg[i].yu],seg[i].val,1);
            ans=max(ans,t[1].maxval);
        }
        printf("%lld\n",ans);
    }
    return 0;
}


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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值