bzoj5132 [CodePlus2017年12月]火锅盛宴

46 篇文章 0 订阅
31 篇文章 0 订阅

http://www.elijahqi.win/2018/02/11/bzoj5132/
题目背景

SkyDec和YJQQQAQ都是Yazid的好朋友。他们都非常喜欢吃火锅。有一天,他们聚在一起,享受一场火锅盛宴。
题目描述

在这场火锅盛宴中,有一个麻辣浓汤锅底的火锅和n种食物,每种食物数量都是无限的。我们用
11

1 至
nn

n 将这些食材编号。

每种食物煮熟所需要的时间不同,第
ii

i 种食物煮熟需要
sis_i

si​ 单位时间。这表示如果你在第
TT

T 个时刻将一个食物
ii

i 下到火锅里,那么它会在第
T+siT+s_i

T+si​ 个时刻被煮熟,并且此后一直会延续被煮熟的状态,直到它被拿走为止。

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

整个火锅盛宴持续
10910^9

109 单位时间。在整个盛宴中,三位好朋友除了谈笑风生之外,最重要的事当然就是吃东西了。在任意整数时刻,都有可能发生下列4种事件中的任意一种,我们用
00

0 至
33

3 之间的整数
opop

op 描述事件类型:

0 id:表示SkyDec往火锅里下了一个编号为
idid

id 的食物。

1:Yazid在锅内搜寻熟了的且最喜欢吃的食物,并拿走一个这种食物。特别地,如果锅里没有熟了的食物,那么Yazid会很愤怒。

2 id:YJQQQAQ在锅内搜寻编号为
idid

id 的食物:如果锅里不存在该种食物,则YJQQQAQ会很愤怒;如果锅里存在熟了的该食物,则YJQQQAQ会取走一个并食用;如果锅里只有未煮熟的该种食物,那么YJQQQAQ会希望知道最接近煮熟的该种食物(即锅内存在时间最长的该种食物)还需要多少时间被煮熟。

3 l r:馋涎欲滴的SkyDec想知道,锅里编号在
[l,r][l,r]

[l,r] 之间的且熟了的食物总共有多少个。
输入输出格式

输入格式:
从标准输入读入数据。

本题包含多组数据,输入的第一行为一个正整数
TT

T ,表示数据组数。接下来依次描述每组数据,对于每组数据:

第一行一个正整数
nn

n ,表示食物的种类数。

第二行
nn

n 个用空格隔开的正整数
s1,s2,……sns_1,s_2,……s_n

s1​,s2​,……sn​ ,描述每种食物煮熟需要的时间。

第三行一个正整数
QQ

Q ,表示事件的数目。

接下来
QQ

Q 行,每行若干个用空格隔开的非负整数,描述一个事件。先是两个整数
t,opt,op

t,op ,分别表示发生事件的时间以及事件的类型。如果
op=0op=0

op=0 或
op=2op=2

op=2 ,则接下来
11

1 个正整数
idid

id ,意义见题目描述;如果
op=1op=1

op=1 ,则接下来没有其他数;如果
op=3op=3

op=3 ,则接下来
22

2 个正整数
l,rl,r

l,r ,意义见题目描述。

我们保证
tt

t 按输入顺序严格递增。

我们保证
1≤t≤1091\leq t\leq 10^9

1≤t≤109 ,
0≤op≤30\leq op\leq 3

0≤op≤3 ,
1≤id≤n1\leq id\leq n

1≤id≤n ,
1≤l≤r≤n1\leq l\leq r\leq n

1≤l≤r≤n 。

输出格式:
对于每个
op≠0op\neq 0

op≠0 的操作,输出一行表示答案。对于不同的
opop

op ,需要输出的内容如下:

对于
op=1op=1

op=1 ,如果Yazid成功取走食物,则输出他取走食物的编号;否则输出”Yazid is angry.”(不含引号,下同)。

对于
op=2op=2

op=2 ,如果YJQQQAQ成功取走食物,则输出”Succeeded!”;否则,如果锅里有未煮熟的该类食物,输出最接近煮熟的该种食物还需要多少时间被煮熟;否则,输出”YJQQQAQ is angry.”。

对于
op=3op=3

op=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.

说明

对于所有数据,保证
T≤4T\leq 4

T≤4 ,保证
n≤100,000n\leq 100,000

n≤100,000 ,
Q≤500,000Q\leq 500,000

Q≤500,000 ,
1≤si≤1081\leq s_i\leq 10^8

1≤si​≤108 。

来自 CodePlus 2017 12 月赛,清华大学计算机科学与技术系学生算法与竞赛协会 荣誉出品。

Credit:idea/王聿中 命题/王聿中 验题/吕时清,杨景钦

Git Repo:https://git.thusaac.org/publish/CodePlus201712

感谢腾讯公司对此次比赛的支持。

一开始和leoly说我可以两棵splay搞搞 leoly说可以啊你写写看 还好我在飞机上又认真想了想发现可以用priority_queue搞定一棵 但还是差点险些tle xx

我首先询问的时候将每个东西煮熟的时间算好 放入优先队列 这时自动按照时间排序 然后每次询问我首先先将煮好的东西提取出来 插入splay中 在splay中我们按照这个下标排序 剩下我们要做的就是模拟他的操作 如果这个东西还没熟 我选择开一个vector来记录 一开始开deque 内存炸了 vector虽然不会自动回收内存 但是他可以将内存自动回收到stl中以便再次利用 还是挺高效方便的 注意需要清空priority_queue&我的vector 针对这个splay我每次需要求一个前驱后驱 什么的 常数就挺大的


#include<queue>
#include<cstdio>
#include<vector>
#include<cstring>
#include<algorithm>
#define N 550000
using namespace std;
inline char gc(){
    static char now[1<<16],*S,*T;
    if (T==S){T=(S=now)+fread(now,1,1<<16,stdin);if (T==S) return EOF;}
    return *S++;
}
inline int read(){
    int x=0,f=1;char ch=gc();
    while(ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=gc();}
    while(ch<='9'&&ch>='0') x=x*10+ch-'0',ch=gc();
    return x*f;
}
int fa[N],val[N],c[N][2],v[N],size[N],cnt,root,n,s[N];
struct node1{
    int t,id;
    inline friend bool operator <(const node1 &a,const node1 &b){
        return a.t>b.t;
    }
};
inline void update(int x){
    size[x]=size[c[x][0]]+size[c[x][1]]+v[x];
}
inline void rotate(int x,int &tar){
    int y=fa[x],z=fa[y];
    if (y==tar) tar=x;else c[z][c[z][1]==y]=x;
    int l=c[y][1]==x,r=l^1;
    fa[c[x][r]]=y;fa[y]=x;fa[x]=z;
    c[y][l]=c[x][r];c[x][r]=y;update(y);update(x); 
}
inline void splay(int x,int &tar){
    while(x!=tar){
        int y=fa[x],z=fa[y];
        if (y!=tar)
            {if (c[y][0]==x^c[z][0]==y) rotate(x,tar);else rotate(y,tar);}
        rotate(x,tar);
    }
}
inline void insert1(int &x,int p,int f){
    if (!x) {x=++cnt;size[x]=v[x]=1;fa[x]=f;val[x]=p;splay(x,root);return;}
    if (p==val[x]) {++v[x];++size[x];splay(x,root);return;}
    if (p<val[x]) insert1(c[x][0],p,x);else insert1(c[x][1],p,x);
}
inline int find(int x,int vv){
    if (!x) return 0;
    if (val[x]==vv) return x;
    if (vv<val[x]) return find(c[x][0],vv);else return find(c[x][1],vv);
}
inline void del(int f,int x){
    --v[x];--size[x];if (!v[x]) c[f][1]=0;update(f);update(fa[f]);
}
int pr,su;
inline void pre(int x,int p){
    if (!x) return;
    if (val[x]<p) pr=x,pre(c[x][1],p);else pre(c[x][0],p);
}
inline void succ(int x,int p){
    if (!x) return;
    if (val[x]>p) su=x,succ(c[x][0],p);else succ(c[x][1],p);
}
inline void print(int x){
    if (c[x][0]) print(c[x][0]);
    printf("%d %d %d\n",val[x],size[x],v[x]);
    if (c[x][1]) print(c[x][1]);
}
vector<node1> a[N];
int main(){
//  freopen("4032.in","r",stdin);
//  freopen("4032.out","w",stdout);
    int T=read();
    while(T--){
        n=read();for (int i=1;i<=n;++i) s[i]=read();int Q=read();cnt=0;
        memset(c,0,sizeof(c));root=0;insert1(root,0,root);insert1(root,n+1,root);
        priority_queue<node1,vector<node1> >q;
        for (int i=1;i<=n;++i) while (a[i].size()) a[i].erase(a[i].begin());
        while(Q--){
            int t=read(),op=read();
            if (!op){
                int id=read();node1 tmp;tmp.id=id;tmp.t=t+s[id];q.push(tmp);
                a[id].push_back(tmp);
            }
            if (op==1){
                node1 tmp;
                while(!q.empty()&&q.top().t<=t) {
                    tmp=q.top();q.pop();
                    insert1(root,tmp.id,root);
                    a[tmp.id].erase(a[tmp.id].begin());
                }
                if(size[root]==2) {puts("Yazid is angry.");continue;} 
                succ(root,0);printf("%d\n",val[su]);succ(root,val[su]);
                splay(su,root);splay(1,c[root][0]);del(1,c[1][1]);
            }
            if (op==2){
                node1 tmp;
                while(!q.empty()&&q.top().t<=t) {
                    tmp=q.top();q.pop();
                    insert1(root,tmp.id,root);
                    a[tmp.id].erase(a[tmp.id].begin());
                }
                int id=read();
                int xx=find(root,id);
                if (xx){
                    puts("Succeeded!");pre(root,id);succ(root,id);
                    splay(su,root);splay(pr,c[root][0]);del(pr,c[pr][1]);
                }else if(a[id].size()) {
                    printf("%d\n",a[id].front().t-t);
                }
                else puts("YJQQQAQ is angry.");
            }
            if (op==3){
                node1 tmp;
                while(!q.empty()&&q.top().t<=t) {
                    tmp=q.top();q.pop();
                    insert1(root,tmp.id,root);
                    a[tmp.id].erase(a[tmp.id].begin());
                }
                int l=read(),r=read();
                pre(root,l),succ(root,r);
                splay(su,root);splay(pr,c[root][0]);printf("%d\n",size[c[pr][1]]);
            }
        }
    }
    return 0;
}

leoly的线段树版本 就是我的splay其实完全可以替换为线段树或者树状数组拥有更多的常数优势 代码简短好写

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#define N 100010
#define pa(a, b) (data){a, b}
using namespace std;

struct data{int x, id;};
int n, sum[N*4], T, w[N], m, x, temp, y, L, R;
deque<int>son[N];

inline char gc(){
    static char now[1<<16], *S, *T;
    if(S==T){T=(S=now)+fread(now, 1, 1<<16, stdin); if(S==T)return EOF;}
    return *S++;
}
inline int read(){
    int x=0; char ch=gc();
    while(ch<'0'||ch>'9')ch=gc();
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0'; ch=gc();}
    return x;
}

inline bool operator>(data a, data b){return a.x>b.x;}

inline void ins(int i, int x, int L, int R){
    sum[i]++; if(L==R)return; int mid=(L+R)>>1;
    if(x<=mid)ins(i<<1, x, L, mid); else ins((i<<1)|1, x, mid+1, R);
}
inline int cp(int i, int L, int R){
    if(!sum[i])return 0; sum[i]--; if(L==R)return L; int mid=(L+R)>>1;
    if(sum[i<<1])return cp(i<<1, L, mid); else return cp((i<<1)|1, mid+1, R);
}
inline int check(int i, int x, int L, int R){
    if(!sum[i])return 0; if(L==R){sum[i]--; return 1;} int mid=(L+R)>>1, s;
    s=x<=mid?check(i<<1, x, L, mid):check((i<<1)|1, x, mid+1, R);
    sum[i]-=s; return s;
}
inline int csum(int i, int a, int b, int L, int R){
    if(a<=L&&R<=b)return sum[i]; int mid=(L+R)>>1, s=0;
    if(a<=mid)s+=csum(i<<1, a, b, L, mid); if(mid<b)s+=csum((i<<1)|1, a, b, mid+1, R);
    return s;
}

int main(){
    T=read(); 
    for(int owo=1; owo<=T; owo++){
        n=read(); for(int i=1; i<=n; i++)w[i]=read();
        priority_queue<data, vector<data>, greater<data> >q;
        for(int i=1; i<=n; i++)son[i].clear();
        memset(sum, 0, sizeof(sum)); m=read();
        for(int i=1; i<=m; i++){
            x=read(); temp=read();
            while(q.size()&&q.top().x<=x){
                y=q.top().id; ins(1, y, 1, n);
                son[y].pop_front(); q.pop();
            }
            if(!temp){y=read(); son[y].push_back(x+w[y]); q.push(pa(x+w[y], y));}
            if(temp==1){
                if(!sum[1]){printf("Yazid is angry.\n"); continue;}
                printf("%d\n", cp(1, 1, n));
            }
            if(temp==2){
                y=read(); if(check(1, y, 1, n)){printf("Succeeded!\n"); continue;}
                if(son[y].size()){printf("%d\n", son[y].front()-x); continue;}
                printf("YJQQQAQ is angry.\n");
            }
            if(temp==3){L=read(); R=read(); printf("%d\n", csum(1, L, R, 1, n));}
        }
    }
    return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值