【loj6258】「CodePlus 2017 12 月赛」火锅盛宴

题目描述
SkyDec和YJQQQAQ都是Yazid的好朋友。他们都非常喜欢吃火锅。有一天,他们聚在一起,享受一场火锅盛宴。
在这场火锅盛宴中,有一个麻辣浓汤锅底的火锅和nnn种食物,每种食物数量都是无限的。我们用111至nnn将这些食材编号。

每种食物煮熟所需要的时间不同,第iii种食物煮熟需要sis_is
​i
​​ 单位时间。这表示如果你在第TTT个时刻将一个食物iii下到火锅里,那么它会在第T+siT+s_iT+s
​i
​​ 个时刻被煮熟,并且此后一直会延续被煮熟的状态,直到它被拿走为止。

Yazid和YJQQQAQ的口味不同:YJQQQAQ觉得所有食物的好吃程度都是相同的;而Yazid则觉得没有两种食材的好吃程度是相同的,并且,巧合的是,编号越小的食物Yazid越喜欢吃。可怜的SkyDec由于不能吃辣,所以只能帮Yazid和YJQQQAQ煮食物。

整个火锅盛宴持续10910^910
​9
​​ 单位时间。在整个盛宴中,三位好朋友除了谈笑风生之外,最重要的事当然就是吃东西了。在任意整数时刻,都有可能发生下列444种事件中的任意一种,我们用000至333之间的整数opopop描述事件类型:

0 id:表示SkyDec往火锅里下了一个编号为ididid的食物。
1:Yazid在锅内搜寻熟了的且最喜欢吃的食物,并拿走一个这种食物。特别地,如果锅里没有熟了的食物,那么Yazid会很愤怒。
2 id:YJQQQAQ在锅内搜寻编号为ididid的食物:如果锅里不存在该种食物,则YJQQQAQ会很愤怒;如果锅里存在熟了的该食物,则YJQQQAQ会取走一个并食用;如果锅里只有未煮熟的该种食物,那么YJQQQAQ会希望知道最接近煮熟的该种食物(即锅内存在时间最长的该种食物)还需要多少时间被煮熟。
3 l r:馋涎欲滴的SkyDec想知道,锅里编号在[l,r][l,r][l,r]之间的且熟了的食物总共有多少个。
整个火锅晚宴中共发生了QQQ个事件,且没有任意两个事件在同一时刻发生。

他们的好朋友Flvze想知道这场火锅晚宴中发生的所有事,所以请你告诉她。
输入格式
从标准输入读入数据。

本题包含多组数据,输入的第一行为一个正整数TTT,表示数据组数。接下来依次描述每组数据,对于每组数据:

第一行一个正整数nnn,表示食物的种类数。

第二行nnn个用空格隔开的正整数
s
1
,
s
2
,

,
s
n
,描述每种食物煮熟需要的时间。

第三行一个正整数QQQ,表示事件的数目。

接下来QQQ行,每行若干个用空格隔开的非负整数,描述一个事件。先是两个整数t,opt,opt,op,分别表示发生事件的时间以及事件的类型。如果op=0op=0op=0或op=2op=2op=2,则接下来111个正整数ididid,意义见题目描述;如果op=1op=1op=1,则接下来没有其他数;如果op=3op=3op=3,则接下来222个正整数l,rl,rl,r,意义见题目描述。

我们保证ttt按输入顺序严格递增。

我们保证1≤t≤1091\leq t\leq 10^91≤t≤10
​9
​​ ,0≤op≤30\leq op\leq 30≤op≤3,1≤id≤n1\leq id\leq n1≤id≤n,1≤l≤r≤n1\leq l\leq r\leq n1≤l≤r≤n。
输出格式
对于每个op≠0op\neq 0op≠0的操作,输出一行表示答案。对于不同的opopop,需要输出的内容如下:

对于op=1op=1op=1,如果Yazid成功取走食物,则输出他取走食物的编号;否则输出”Yazid is angry.”(不含引号,下同)。
对于op=2op=2op=2,如果YJQQQAQ成功取走食物,则输出”Succeeded!”;否则,如果锅里有未煮熟的该类食物,输出最接近煮熟的该种食物还需要多少时间被煮熟;否则,输出”YJQQQAQ is angry.”。
对于op=3op=3op=3,输出锅内编号在指定范围内的熟食的数量。
输出到标准输出。
样例
样例1输入

1
2
1 100
10
1 0 2
2 0 1
3 2 1
4 2 2
5 2 1
200 0 1
201 3 1 2
202 1
203 1
204 1
样例1输出

Succeeded!
97
YJQQQAQ is angry.
2
1
2
Yazid is angry.
数据范围与提示
子任务

测试点编号 n≤n\leqn≤ Q≤Q\leqQ≤ 特殊约定 测试点分值
1 500500500 100010001000 无 8
2-3 101010 300,000300,000300,000 无 6
4-5 100,000100,000100,000 所有si=1s_i=1s
​i
​​ =1 8
6-7 所有sis_is
​i
​​ 都相同 11
8-9 op≠3op\neq 3op≠3 7
10-11 无 12
12-13 500,000500,000500,000 2
对于所有数据,保证T≤4T\leq 4T≤4,保证n≤100,000n\leq 100,000n≤100,000,Q≤500,000Q\leq 500,000Q≤500,000,1≤si≤1081\leq s_i\leq 10^81≤s
​i
​​ ≤10
​8
​​ 。

来自 CodePlus 2017 12 月赛,清华大学计算机科学与技术系学生算法与竞赛协会 荣誉出品。
Credit:idea/王聿中 命题/王聿中 验题/吕时清,杨景钦
Git Repo:https://git.thusaac.org/publish/CodePlus201712
感谢腾讯公司对此次比赛的支持。

题解
堆+线段树

op=0:将物品成熟时间t+s[i]加入小根堆q1,每次操作前将成熟时间小于t的食材编号加入小根堆q2。对于每种食材开一个小根堆,将t+s[i]加入堆q3[i]。线段树编号i位置+1。
op=1:熟的食材且编号最小,即q2所维护内容,跟新线段树。
op=2:查找对应编号食材,即q3所维护内容。
op=3:线段树查询即可。

代码

#include<bits/stdc++.h>
#define ll long long
#define pa pair<int,int>
using namespace std;
inline ll read()
{
    ll x=0,f=1;char ch=getchar();
    while(ch>'9'||ch<'0'){if (ch=='-') f=-1;ch=getchar();}
    while(ch<='9'&&ch>='0'){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}
    return x*f;
}
int t[400005],n,Q,s[100005],Rest[100005];
priority_queue<pa,vector<pa>,greater<pa> >q1;
priority_queue<int,vector<int>,greater<int> >q2,S[100005];
void modify(int k,int l,int r,int x,int y)
{
    t[k]+=y;
    if (l==r)return;
    int mid=(l+r)>>1;
    if (x<=mid) modify(k<<1,l,mid,x,y);
    else modify(k<<1|1,mid+1,r,x,y);
}
int query(int k,int l,int r,int x,int y)
{
    if (l==x&&r==y) return t[k];
    int mid=(l+r)>>1;
    if (y<=mid) return query(k<<1,l,mid,x,y);
    else if (x>mid) return query(k<<1|1,mid+1,r,x,y);
    else return query(k<<1,l,mid,x,mid)+query(k<<1|1,mid+1,r,mid+1,y);
}
void solve()
{
    n=read();
    for (int i=1;i<=n;i++) s[i]=read();
    for (int i=1;i<=n;i++) Rest[i]=0;
    for (int i=1;i<=400004;i++) t[i]=0;
    while (!q1.empty()) q1.pop();while (!q2.empty()) q2.pop();
    for (int i=1;i<=n;i++) while (!S[i].empty()) S[i].pop(); 
    Q=read();
    while (Q--)
    {
        int tim=read(),op=read();
        while (!q1.empty()&&q1.top().first<=tim)
        {
            q2.push(q1.top().second);
            modify(1,1,n,q1.top().second,1);
            q1.pop();
        }
        if (op==0)
        {
            int id=read();
            q1.push(make_pair(tim+s[id],id));
            S[id].push(tim+s[id]);
        }
        else if (op==1)
        {
            while (!q2.empty()&&Rest[q2.top()]) Rest[q2.top()]--,q2.pop();
            if (q2.empty()) puts("Yazid is angry.");
            else
            {
                printf("%d\n",q2.top());
                modify(1,1,n,q2.top(),-1);
                S[q2.top()].pop();
                q2.pop();
            }
        }
        else if (op==2)
        {
            int id=read();
            if (S[id].empty()) puts("YJQQQAQ is angry.");
            else
            {
                if (S[id].top()<=tim)
                {
                    puts("Succeeded!");
                    modify(1,1,n,id,-1);
                    Rest[id]++;
                    S[id].pop();
                }
                else printf("%d\n",S[id].top()-tim);
            }
        }
        else 
        {
            int l=read(),r=read();
            printf("%d\n",query(1,1,n,l,r));
        }
    }
}
int main()
{
    int Case=read();
    while (Case--) solve();
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值