POJ2482 Stars in Your Window 线段树 二维转换一维 STL

解题思路: 首先注意到最优解肯定是窗子的右上角(或其他角)在某个星星位置处(这里的在是模糊的在,略微比星星的位置大一点,能包含这个星星就行)。这样就将问题变成离散空间上的问题了。然后问题关键就是将二维问题变成一维问题,先只考虑x轴方向的一维,可以想到一个星星的起到的作用是一条长度为w的线段,然后答案就是找到被最多线段覆盖的某点,就是区间最值问题了。那么再考虑y轴这一维,这一维可以认为是线段的存活时间。那么将星星分成两条线段,一个代表出生,一个代表死亡,然后按照y坐标顺序插入星星(因为在每个y坐标出要么产生一个新的线段,要么减少一个线段,都会改变已有线段树的状态),线段树的作用就是维护一个区间最值。

我觉得类似的问题有林涛论文《线段树的应用》中的例题 “蛇”,也是有类似这种二维变一维,存活时间的思想。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
using namespace std;
#define maxn 20005
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
typedef long long ll;
vector<ll> X;
struct StarType{
    ll x,y,c;
    StarType(){}
    StarType(ll x,ll y,ll c)
    {
        this->x=x,this->y=y,this->c=c;
    }
}Star[maxn];
bool cmp(const StarType& a,const StarType& b)
{
    if(a.y==b.y)
        return a.c<0;
    return a.y<b.y;
}
ll Tree[maxn<<2],Lazy[maxn<<2];
void Build()
{
    memset(Tree,0,sizeof(Tree));
    memset(Lazy,0,sizeof(Lazy));
}
void PushDown(int rt)
{
    Tree[rt]+=Lazy[rt];
    Lazy[rt<<1]+=Lazy[rt];
    Lazy[rt<<1|1]+=Lazy[rt];
    Lazy[rt]=0;
}
void Update(ll val,int L,int R,int l,int r,int rt)
{
    if(L<=l&&r<=R)
    {
        Lazy[rt]+=val;
        return ;
    }
    if(L>r||R<l)
        return ;
    if(Lazy[rt]!=0)
        PushDown(rt);
    int mid=(l+r)>>1;
    Update(val,L,R,lson);
    Update(val,L,R,rson);
    Tree[rt]=max(Tree[rt<<1]+Lazy[rt<<1],Tree[rt<<1|1]+Lazy[rt<<1|1]);
    return ;
}  
ll Query()
{
    return Tree[1]+Lazy[1];
}  
void Init()
{
    X.clear();
    Build();
}
int main()
{
    int n,w,h,i,j,L,R,l,r;
    ll ans;
    while(scanf("%d %d %d",&n,&w,&h)!=EOF)
    {
        Init();
        for(i=0;i<n;++i)
        {
            scanf("%lld %lld %lld",&Star[i].x,&Star[i].y,&Star[i].c);
            Star[i+n].x=Star[i].x,Star[i+n].y=Star[i].y+h,Star[i+n].c=-Star[i].c;
            X.push_back(Star[i].x);
        }
        sort(Star,Star+2*n,cmp);
        X.resize(distance(X.begin(),unique(X.begin(),X.end())));
        sort(X.begin(),X.end());
        l=1,r=X.end()-X.begin()+1;
        ans=0;
        for(i=0;i<2*n;++i)
        {
            L=lower_bound(X.begin(),X.end(),Star[i].x)-X.begin()+1;
            R=lower_bound(X.begin(),X.end(),Star[i].x+w)-X.begin();
            Update(Star[i].c,L,R,l,r,1);
            ans=max(ans,Query());
        }
        printf("%lld\n",ans);
    }
    return 0;
}


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值