「CodePlus 2017 12 月赛」火锅盛宴(模拟+树状数组)

本文介绍了一道ACM竞赛中的煮饭问题,并详细解释了解题思路:使用优先队列进行排序,通过树状数组追踪食物状态。文章提供完整的C++代码实现,包括输入输出流程、关键操作函数及主要数据结构。

  1A,拿来练手的好题

  用一个优先队列按煮熟时间从小到大排序,被煮熟了就弹出来。

  用n个vector维护每种食物的煮熟时间,显然是有序的。

  用树状数组维护每种煮熟食物的数量。

  每次操作前把优先队列里煮熟时间<=当前时间的弹出,BIT上+1。

  每次0操作把食物塞进优先队列和vector

  每次1操作先看看树状数组里有没有数,没有输出angry,有的话在树状数组上二分找到最小的数。

  每次2操作先看看树状数组里有没有这一种数,有的话输出并-1,没有的话看看vector有没有,有的话输出时间差,没有的话输出angry。

  没了,写得行云流水。

#include<iostream>
#include<cstring>
#include<cstdlib>
#include<cstdio>
#include<queue>
#include<vector>
#define ll long long
using namespace std;
const int maxn=500010;
struct poi{int pos, tim;};
priority_queue<poi>q;
bool operator<(poi a, poi b){return a.tim>b.tim;}
int n, Q, mx, t, ty, x, l, r, T;
int tree[1<<20], fir[maxn], s[maxn];
vector<int>v[maxn];
inline void read(int &k)
{
    int f=1; k=0; char c=getchar();
    while(c<'0' || c>'9') c=='-' && (f=-1), c=getchar();
    while(c<='9' && c>='0') k=k*10+c-'0', c=getchar();
    k*=f;
}
inline void add(int x, int delta){for(;x<=mx;x+=x&-x) tree[x]+=delta;}
inline int query(int x){int sum=0; for(;x;x-=x&-x) sum+=tree[x]; return sum;}
inline void yazid()
{
    if(!tree[mx]) {puts("Yazid is angry."); return;}
    int l=0, r=mx, k=1;
    while(l<r)
    {
        int mid=(l+r)>>1;
        if(tree[mid]>=k) r=mid;
        else k-=tree[mid], l=mid+1;
    }
    add(l, -1); printf("%d\n", l);
    return;
}
inline void yjqqaq(int t, int id)
{
    if(query(id)-query(id-1)) {puts("Succeeded!"); add(id, -1); return;}
    if(v[id].size()==fir[id]) {puts("YJQQQAQ is angry."); return;}
    printf("%d\n", v[id][fir[id]]-t); return;
}
inline void clear()
{
    memset(tree, 0, (mx+1)<<2);
    memset(fir, 0, (n+1)<<2);
    while(!q.empty()) q.pop();
    for(int i=1;i<=n;i++) v[i].clear();
}
int main()
{
    read(T);
    while(T--)
    {
        read(n); mx=1; while(mx<=n) mx<<=1; clear();
        for(int i=1;i<=n;i++) read(s[i]);
        read(Q);
        for(int i=1;i<=Q;i++)
        {
            read(t); read(ty);
            while(!q.empty())
            {
                poi now=q.top();
                if(now.tim<=t) q.pop(), add(now.pos, 1), fir[now.pos]++;
                else break; 
            }
            if(!ty) read(x), q.push((poi){x, t+s[x]}), v[x].push_back(t+s[x]);
            else if(ty==1) yazid();
            else if(ty==2) read(x), yjqqaq(t, x);
            else read(l), read(r), printf("%d\n", query(r)-query(l-1));
        }
    }
}
View Code

 

转载于:https://www.cnblogs.com/Sakits/p/8099398.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值