SGU Ice-cream Tycoon 线段树+离散化

已单价划分区间,线段树节点保存数量和总价。优先处理单价较小的(即左节点)。

成段更新,延迟标记。这个题目存在卖与不卖两种情况,所以第一遍先查询一下到底能不能卖,如果能卖,再进行处理(下面代码的deal函数)。

因为数据范围很大,需要用__int64 保存,但是内存给的很小,所以我们需要离散化处理。把单价离散化,在具体计算的时候再搞回来。

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define MAXN 400009
#define nmaxn 100009
#define LL __int64
struct node
{
    bool col;
    LL num;
    LL tot;
} sum[MAXN];
LL  se[nmaxn];
int k;
//离散化,二分查找
int sea(int l,int r,LL va)
{
    while(l<=r)
    {
        int mid=(l+r)>>1;
        if(se[mid]==va)return mid;
        else if(se[mid]<va)l=mid+1;
        else r=mid-1;
    }
}
//向上更新
void update(int rt)
{
    sum[rt].num=sum[rt<<1].num+sum[rt<<1|1].num;
    sum[rt].tot=sum[rt<<1].tot+sum[rt<<1|1].tot;
}
//向下更新延迟标记
void downdate(int rt)
{
    if(sum[rt].col==1)
    {
        sum[rt<<1].col=sum[rt<<1|1].col=1;
        sum[rt].col=0;
        sum[rt<<1].num=sum[rt<<1|1].num=0;
        sum[rt<<1].tot=sum[rt<<1|1].tot=0;
    }
    return ;
}
//查询卖不卖
bool query(int l,int r,int rt,LL number,LL totsum)
{
    if(totsum<0)return false;
    if(sum[rt].num<number)return false;
    else if(sum[rt].num==number&&sum[rt].tot>totsum)return false;
    else if(sum[rt].num==number&&sum[rt].tot<=totsum)return true;
    else
    {
        if(l==r)
        {
            if((LL)se[l]*number>totsum)return false;
            else return true;
        }
        downdate(rt);
        int m=(l+r)>>1;
        if(sum[rt<<1].num>=number)return query(lson,number,totsum);
        else return query(rson,number-sum[rt<<1].num,totsum-sum[rt<<1].tot);
    }
}
//如果能卖,把相应的东西卖掉,加入在【l,r】的单价范围内都能卖,那么在这段线段树上进行延时标记
void deal(int l,int r,int rt,LL number,LL totsum)
{
    if(number==0||totsum<=0)return ;
    if(l==r)
    {
        sum[rt].num-=number;
        sum[rt].tot-=(LL)se[l]*number;
        return;
    }
    int m=(l+r)>>1;
    downdate(rt);
    if(sum[rt<<1].num>number)deal(lson,number,totsum);
    else
    {
        sum[rt<<1].col=1;
        deal(rson,number-sum[rt<<1].num,totsum-sum[rt<<1].tot);
        sum[rt<<1].num=sum[rt<<1].tot=0;
    }
    update(rt);
    return ;
}
//进货的情况 在单价为p的叶子节点上更新信息
void add(int l,int r,int rt,int p,LL number)
{
    if(l==r)
    {
        sum[rt].num+=number;
        sum[rt].tot+=(LL)se[p]*number;
        return ;
    }
    downdate(rt);
    int m=(l+r)>>1;
    if(m>=p)add(lson,p,number);
    else add(rson,p,number);
    update(rt);
    return ;
}
//建树,初始化线段树
void build(int l,int r,int rt)
{
    if(l==r)
    {
        sum[rt].col=sum[rt].num=sum[rt].tot=0;
        return ;
    }
    int m=(l+r)>>1;
    build(lson);
    build(rson);
    update(rt);
}
LL y[nmaxn],x[nmaxn];
char s1[nmaxn][30];
int main()
{
    LL n,m,i,j,z;
    int num=1;
    build(1,nmaxn,1);
    i=0;
    while(scanf("%s%I64d%I64d",s1[i],&x[i],&y[i])!=-1)
    {
        //离散化单价
        if(strcmp(s1[i],"ARRIVE")==0)
        {
            se[num++]=y[i];
        }
        i++;
    }
    z=i;
    //离散化
    sort(se+1,se+num);
    k=1;
    for(i=2; i<num; i++)
    {
        if(se[i]!=se[i-1])se[++k]=se[i];
    }
    //依次输出结果
    for(i=0; i<z; i++)
    {
        if(strcmp(s1[i],"ARRIVE")==0)
        {
            int temy=sea(1,k,y[i]);
            add(1,nmaxn,1,temy,x[i]);
        }
        else
        {
            if(query(1,nmaxn,1,x[i],y[i]))
            {
                printf("HAPPY\n");
                deal(1,nmaxn,1,x[i],y[i]);
            }
            else printf("UNHAPPY\n");
        }
    }
    return 0;
}
感谢ink同学的无私帮助

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值