[POJ2482]Stars in Your Window(线段树)

题目:

我是超链接

题意:

假定天空是一个平面,每个星星都有一个坐标(x,y),每颗星星都有一个亮度C,代表它的亮度。窗户是长方形的,有固定的长和宽,边平行于x轴和y轴。你的任务是告诉我如何摆放窗户,才能获得在窗口内所有星星的亮度总和最大值。注意,边框的星星不算。窗口可以被平移,但不允许旋转。
输入
在输入中有几个测试样例例。每一行的第一行包含3个整数:n,w,h,表示星形的数目,矩形窗口的水平长度和垂直高度。然后N行如下,有3个整数分别为:X,Y,C,表示星星位置(x,y)和每个恒星的亮度。没有两颗星星在同一点上。
天空中至少有1颗,最多有10000颗星星。1 = < W,h <= 1000000,0 =< x,y ,C < 2^31。
输出
对于每个测试样例,输出窗口内所有星星的亮度总和最大值。

题解:

原来只要转换一下,就能把其转换为求线段区间的最大值,每个星星所能影响的范围[(x,y),(x+w-1,y+h-1)]且有一权值,它们重合就表示能被这个矩形框在一起,也就是说,只要求出重合的矩形的权值最大就行了。

以x从小到大排序,y值离散化,投影到y轴上,那么对于每个星星的纵坐标,y,y+h-1就是每个星星可以影响到的矩形 然后x,x+w-1就是一个进入事件和一个出去事件,其所带的值互为相反数。maxx保存当前的最大值 当所有的矩形都遍历一遍 取其中的最大值就是ans

要特别注意这个数据范围,因为y是顶着上限的,一加上h就更越过上限了

代码:

#include <map>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define LL long long 
using namespace std;
const int N=160005;
LL maxx[N],delta[N],ls[N];
map<int,int>mp;
struct hh{LL x,y1,y2,c;}seg[N];
int cmp(hh a,hh b){return a.x<b.x || (a.x==b.x && a.c>b.c);}
void updata(int now){maxx[now]=max(maxx[now<<1],maxx[now<<1|1]);}
void pushdown(int now)
{
    if (delta[now])
    {
        delta[now<<1]+=delta[now];
        delta[now<<1|1]+=delta[now];
        maxx[now<<1]+=delta[now];
        maxx[now<<1|1]+=delta[now];
        delta[now]=0;
    }
}
void change(int now,int l,int r,int lrange,int rrange,LL v)
{
    if (lrange<=l && rrange>=r) {delta[now]+=(LL)v; maxx[now]+=(LL)v; return;}
    int mid=(l+r)>>1;
    pushdown(now);
    if (lrange<=mid) change(now<<1,l,mid,lrange,rrange,v);
    if (rrange>mid) change(now<<1|1,mid+1,r,lrange,rrange,v);
    updata(now);
}
int main()
{
//  freopen("stars.in","r",stdin);
//  freopen("stars.out","w",stdout);
    int n,w,h;
    while (scanf("%d%d%d",&n,&w,&h)!=EOF)
    {
        int num=0;LL ans=0,x,y,c;
        memset(maxx,0,sizeof(maxx));
        memset(delta,0,sizeof(delta));
        for (int i=1;i<=n;i++)
        {
            scanf("%lld%lld%lld",&x,&y,&c);
            seg[++num].x=x; seg[num].y1=y; seg[num].y2=y+h-1; seg[num].c=c; ls[num]=y;
            seg[++num].x=x+w-1; seg[num].y1=y; seg[num].y2=y+h-1; seg[num].c=-c; ls[num]=y+h-1;
        }
        sort(ls+1,ls+num+1);
        int s=unique(ls+1,ls+num+1)-ls-1;
        mp[ls[1]]=1;int now=1;
        for (int i=2;i<=num;i++)
          if (ls[i]==ls[i-1]) mp[ls[i]]=now;
          else now++,mp[ls[i]]=now;

        for (int i=1;i<=num;i++)
          seg[i].y1=mp[seg[i].y1],seg[i].y2=mp[seg[i].y2];

        sort(seg+1,seg+num+1,cmp);
        for (int i=1;i<=num;i++)
        {
            change(1,1,now,seg[i].y1,seg[i].y2,seg[i].c);
            ans=max(ans,maxx[1]);
        }
        printf("%lld\n",ans);
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值