「CodePlus 2017 12 月赛」火锅盛宴

n<=100000种食物,给每个食物煮熟时间,有q<=500000个操作:在某时刻插入某个食物;查询熟食中编号最小的并删除之;查询是否有编号为id的食物,如果有查询是否有编号为id的熟食,如果有熟食删除之,否则输出其离煮熟的最小时间;查询编号在[L,R]的熟食有多少。保证操作时间递增。

可以发现:针对某种食物的信息维护只需要知道其未煮熟的食物中煮熟时间的最小值,而所有的熟食都可以一起维护。为此可以:对每个食物开个队列存未熟食物,对所有食物开个优先队列以便及时把熟食从队列中提出来,并开个以编号为下标的“东西”来维护每个编号的数量和区间信息。

由于只需要单点修改、区间查询,可以用BIT。至于查熟食中的编号最小可以用BIT上倍增。

这里比较脑残就写了线段树。。然而被卡常卡死了。

  1 #include<stdio.h>
  2 #include<string.h>
  3 #include<algorithm>
  4 #include<stdlib.h>
  5 #include<queue>
  6 //#include<queue>
  7 //#include<math.h>
  8 //#include<time.h>
  9 //#include<iostream>
 10 using namespace std;
 11
 12 int T,n,m;
 13 #define maxn 200011
 14 #define maxq 500011
 15
 16 struct SMT
 17 {
 18     struct Node
 19     {
 20         int sum;
 21         int ls,rs;
 22     }a[maxn<<1];
 23     int size;
 24     void build(int &x,int L,int R)
 25     {
 26         x=++size; a[x].sum=0;
 27         if (L==R) {a[x].ls=a[x].rs=0; return;}
 28         const int mid=(L+R)>>1;
 29         build(a[x].ls,L,mid); build(a[x].rs,mid+1,R);
 30     }
 31     void build() {size=0; int x; build(x,1,n);}
 32     void up(int x) {a[x].sum=a[a[x].ls].sum+a[a[x].rs].sum;}
 33     int ql,qr,v;
 34     bool Add(int x,int L,int R)
 35     {
 36         if (L==R)
 37         {
 38             if (v==-1 && a[x].sum==0) return 0;
 39             a[x].sum+=v; return 1;
 40         }
 41         else
 42         {
 43             const int mid=(L+R)>>1;bool ans;
 44             if (ql<=mid) ans=Add(a[x].ls,L,mid);
 45             else ans=Add(a[x].rs,mid+1,R);
 46             up(x); return ans;
 47         }
 48     }
 49     bool add(int x,int v) {ql=x; this->v=v; return Add(1,1,n);}
 50     int Find(int x,int L,int R)
 51     {
 52         if (L==R) return L;
 53         const int mid=(L+R)>>1;
 54         if (a[a[x].ls].sum>0) return Find(a[x].ls,L,mid);
 55         return Find(a[x].rs,mid+1,R);
 56     }
 57     int find() {return Find(1,1,n);}
 58     int Query(int x,int L,int R)
 59     {
 60         if (ql<=L && R<=qr) return a[x].sum;
 61         int mid=(L+R)>>1,ans=0;
 62         if (ql<=mid) ans+=Query(a[x].ls,L,mid);
 63         if (qr> mid) ans+=Query(a[x].rs,mid+1,R);
 64         return ans;
 65     }
 66     int query(int L,int R) {ql=L; qr=R; return Query(1,1,n);}
 67 }smt;
 68
 69 struct qnode
 70 {
 71     int v,id;
 72     bool operator > (const qnode &b) const {return v>b.v;}
 73 };
 74 priority_queue<qnode,vector<qnode>,greater<qnode> > qtot;
 75 queue<int> q[maxn];
 76
 77 int a[maxn];
 78 int qread()
 79 {
 80     char c;int s=0; while (!((c=getchar())>=‘0‘ && c<=‘9‘));
 81     do s=s*10+c-‘0‘; while ((c=getchar())>=‘0‘ && c<=‘9‘); return s;
 82 }
 83 void write(int x)
 84 {
 85     if (!x) {putchar(‘0‘);putchar(‘\n‘);return;}
 86     char buf[15]; int lb=0;
 87     while (x) {buf[++lb]=x%10; x/=10;}
 88     for (;lb;lb--) putchar(buf[lb]+‘0‘); putchar(‘\n‘);
 89 }
 90 int main()
 91 {
 92     scanf("%d",&T);
 93 while (T--)
 94 {
 95     scanf("%d",&n);
 96     for (int i=1;i<=n;i++) a[i]=qread();
 97     for (int i=1;i<=n;i++) while (!q[i].empty()) q[i].pop();
 98     while (!qtot.empty()) qtot.pop();
 99     smt.build();
100     scanf("%d",&m);
101     int t,op,id,x,y;
102     while (m--)
103     {
104         t=qread(),op=qread();
105         while (!qtot.empty() && qtot.top().v<=t) smt.add(qtot.top().id,1),q[qtot.top().id].pop(),qtot.pop();
106         if (op==0)
107         {
108             id=qread();
109             q[id].push(t);
110             qtot.push((qnode){t+a[id],id});
111         }
112         else if (op==1)
113         {
114             if (smt.a[1].sum==0) puts("Yazid is angry.");
115             else
116             {
117                 int ans=smt.find();
118                 write(ans);
119                 smt.add(ans,-1);
120             }
121         }
122         else if (op==2)
123         {
124             id=qread();
125             if (smt.add(id,-1)) puts("Succeeded!");
126             else if (q[id].empty()) puts("YJQQQAQ is angry.");
127             else write(q[id].front()+a[id]-t);
128         }
129         else
130         {
131             x=qread(),y=qread();
132             write(smt.query(x,y));
133         }
134     }
135 }
136     return 0;
137 }

时间: 2024-10-02 02:22:48

「CodePlus 2017 12 月赛」火锅盛宴的相关文章

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

1A,拿来练手的好题 用一个优先队列按煮熟时间从小到大排序,被煮熟了就弹出来. 用n个vector维护每种食物的煮熟时间,显然是有序的. 用树状数组维护每种煮熟食物的数量. 每次操作前把优先队列里煮熟时间<=当前时间的弹出,BIT上+1. 每次0操作把食物塞进优先队列和vector 每次1操作先看看树状数组里有没有数,没有输出angry,有的话在树状数组上二分找到最小的数. 每次2操作先看看树状数组里有没有这一种数,有的话输出并-1,没有的话看看vector有没有,有的话输出时间差,没有的话输出

走进矩阵树定理--「CodePlus 2017 12 月赛」白金元首与独舞

n,m<=200,n*m的方阵,有ULRD表示在这个格子时下一步要走到哪里,有一些待决策的格子用.表示,可以填ULRD任意一个,问有多少种填法使得从每个格子出发都能走出这个方阵,答案取模.保证未确定的格子<=300. ...一脸懵逼地写了原本30实际20的暴力然后跪着啃了下论文 然而什么都没啃懂不如结论记下来: 首先矩阵行列式的定义:一个n*n的矩阵,行列式值为$\sum_{b是n的一个排列} \ \ \ \ \ ( (-1)^{b的逆序对数} \ \ \ \ \ * \prod_{i=1}^

【LIbreOJ】#6256. 「CodePlus 2017 12 月赛」可做题1

[题意]定义一个n阶正方形矩阵为"巧妙的"当且仅当:任意选择其中n个不同行列的数字之和相同. 给定n*m的矩阵,T次询问以(x,y)为左上角的k阶矩阵是否巧妙.n,m<=500,T<=10^5. [算法]数学 [题解] 可以证明每个矩阵是巧妙的当且仅当其每个2阶子矩阵均是巧妙的: 必要性:若该矩阵有一个不巧妙的2阶子矩阵,则其他部分选择相同的情况下(不涉及此两行列),这两行列的和不同,所以该矩阵不是巧妙的. 观察一个巧妙的2阶子矩阵 a1 a2 b1 b2 由a1+b2=a

「CodePlus 2017 12 月赛」白金元首与独舞

description 题面 data range \[ 1 \leq T \leq 10, 1 \leq n, m \leq 200 , 0 \leq k \leq \min(nm, 300)\] solution 矩阵树定理 求无向图的生成树个数 度数矩阵-邻接矩阵 去掉一行一列求行列式 为了保证精度可以辗转相除 这里是模意义下的 const int mod=998244353; int a[305][305]; il int gauss(int n){ RG int ans=1; for(

[LOJ 6249]「CodePlus 2017 11 月赛」汀博尔

Description 有 n 棵树,初始时每棵树的高度为 H_i,第 i 棵树每月都会长高 A_i.现在有个木料长度总量为 S 的订单,客户要求每块木料的长度不能小于 L,而且木料必须是整棵树(即不能为树的一部分).现在问你最少需要等多少个月才能满足订单. Input 第一行 3 个用空格隔开的非负整数 n,S,L,表示树的数量.订单总量和单块木料长度限制.第二行 n 个用空格隔开的非负整数,依次为 H1,H2,…,Hn.第三行 n 个用空格隔开的非负整数,依次为 A1,A2,…,An. Ou

「CodePlus 2017 11 月赛」汀博尔 (二分答案)

题目链接:https://loj.ac/problem/6249 题意:有 n 棵树,初始时每棵树的高度为 H?i?,第 i 棵树每月都会长高 A?i??.现在有个木料长度总量为 S 的订单,客户要求每块木料的长度不能小于 L,而且木料必须是整棵树(即不能为树的一部分). 现在问你最少需要等多少个月才能满足订单.(数据范围:1<=n<=200000,1<=S,L<=1e18,1<=Hi,Ai<=1e9) 题解:很显然二分答案.上界不能直接选择1e18,会爆long lo

「CodePlus 2017 11 月赛」可做题

这种题显然先二进制拆位,显然改的位置显然只有每一段确定的数的开头和结尾,只需要对于每一个可决策位置都尝试一下填1和0,然后取min即可. #include<iostream> #include<cstring> #include<cstdlib> #include<cstdio> #include<algorithm> #define ll long long using namespace std; const int maxn=500010;

「CodePlus 2017 11 月赛」Yazid 的新生舞会(树状数组/线段树)

学习了新姿势..(一直看不懂大爷的代码卡了好久T T 首先数字范围那么小可以考虑枚举众数来计算答案,设当前枚举到$x$,$s_i$为前$i$个数中$x$的出现次数,则满足$2*s_r-r > 2*s_l-l$的区间$[l+1,r]$其众数为$x$,这个显然可以用一个数据结构来维护. 直接扫一遍效率是$O($数字种类数$*nlogn)$的,无法承受,但是我们发现,对于每一段非$x$的数,$2*s_i-i$是公差为$-1$的等差数列,所以它们对答案的贡献实际上可以一次性计算.设$L$为一段非$x$数

CodePlus2017 12月月赛 div2火锅盛宴

当时看到这道题感觉真是难过,我数据结构太弱啦. 我们来看看需要求什么: 1.当前熟了的食物的最小id 2.当前熟了的食物中有没有编号为id的食物 3.当前没熟的食物中有没有编号为id的食物 4.当前没熟的食物中编号为id的食物最接近煮熟的还需要多久才会熟 5.当前熟了的食物中编号在[l,r]之间的有多少个 我们需要维护的操作是: 1.往当前的锅里面加一个编号为id的生食物 2.每个时刻锅里面哪些生的食物要变熟 3.吃掉(删除)一个熟了的食物 感觉这种题真考人做题的毅力,求的东西好杂感觉脑子里都乱