SGU 311 Ice-cream Tycoon(线段树)

题目链接:http://acm.sgu.ru/problem.php?contest=0&problem=311

题意:一个商店,有两种操作:(1)ARRIVE n c表示进货n个,每个c元。(2)BUY n t表示一个买货的人要买n个,一共拿了t元钱。如果现在店里的货的数量大于等于n且最便宜的n个的价格小于等于t则将最便宜的卖给他。否则不卖。

思路:线段树的节点保存该段货物的数量和总价格,另外增加一个标志标记该段内是否被卖完。标记每次向下传递。注意在计算最便宜的n个的价格时向下传递标志时要向上更新sum和value值。因为若这次不向上更新,若本次的价格和大于t则不会再进行删掉前n个的操作,就会出错。



const int N=100005;
const int M=300005;

struct query
{
    char cmd[10];
    i64 n,c;
};

struct node
{
    i64 sum,value;
    int L,R,mid,flag;
};

query q[N];
vector<i64> V;
map<i64,int> Map;
int n,m;
node a[M];

void build(int t,int L,int R)
{
    a[t].L=L;
    a[t].R=R;
    a[t].mid=(L+R)>>1;
    a[t].flag=0;
    a[t].sum=a[t].value=0;
    if(L==R) return;
    build(t*2,L,a[t].mid);
    build(t*2+1,a[t].mid+1,R);
}

void mark(int u)
{
    if(u>M) return;
    a[u].flag=1;
    a[u].sum=a[u].value=0;
}

void down(int t)
{
    if(t>M||!a[t].flag) return;
    a[t].flag=0;
    mark(t*2);mark(t*2+1);
}

void up(int t)
{
    a[t].sum=a[t*2].sum+a[t*2+1].sum;
    a[t].value=a[t*2].value+a[t*2+1].value;
}

void insert(int t,int pos,i64 n)
{
    down(t);
    if(a[t].L==a[t].R)
    {
        a[t].sum+=n;
        a[t].value+=V[pos-1]*n;
        return;
    }
    if(pos<=a[t].mid) insert(t*2,pos,n);
    else insert(t*2+1,pos,n);
    up(t);
}


i64 get(int t,i64 n)
{
    down(t);
    if(n==a[t].sum) return a[t].value;
    if(a[t].L==a[t].R) return a[t].value/a[t].sum*n;
    up(t);
    if(n<=a[t*2].sum) return get(t*2,n);
    return a[t*2].value+get(t*2+1,n-a[t*2].sum);
}

void del(int t,i64 n)
{
    down(t);
    if(n==a[t].sum)
    {
        mark(t);
        return;
    }
    if(a[t].L==a[t].R)
    {
        a[t].value-=a[t].value/a[t].sum*n;
        a[t].sum-=n;
        return;
    }
    if(n<=a[t*2].sum) del(t*2,n);
    else
    {
        del(t*2+1,n-a[t*2].sum);
        mark(t*2);
    }
    up(t);
}

void deal(i64 n,i64 t)
{
    if(a[1].sum<n||get(1,n)>t) puts("UNHAPPY");
    else puts("HAPPY"),del(1,n);
}


int main()
{
    while(scanf("%s%lld%lld",q[n+1].cmd,&q[n+1].n,&q[n+1].c)!=-1)
    {
        n++;
        if(q[n].cmd[0]=='A') V.pb(q[n].c);
    }
    sort(V.begin(),V.end());
    m=unique(V.begin(),V.end())-V.begin();
    int i,k;
    FOR0(i,m) Map[V[i]]=i+1;
    build(1,1,m);
    FOR1(i,n)
    {
        if(q[i].cmd[0]=='A')
        {
            k=Map[q[i].c];
            insert(1,k,q[i].n);
        }
        else deal(q[i].n,q[i].c);
    }
	return 0;
}

  

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值