队列

队列是一种先进先出的线性数据结构
一般来说,元素从右端(队尾)入队,从左端(队头)出队
可以将队头队尾相连,优化空间利用,这就是“循环队列”
一般直接用STL就好啦

模板

  1. // 普通队列
  2. // hh 表示队头,tt表示队尾
  3. int q[N], hh = 0, tt = -1;
  4. // 向队尾插入一个数
  5. q[ ++ tt] = x;
  6. // 从队头弹出一个数
  7. hh ++ ;
  8. // 队头的值
  9. q[hh];
  10. // 判断队列是否为空
  11. if (hh <= tt)
  12. {
  13. }
  14. // 循环队列
  15. // hh 表示队头,tt表示队尾的后一个位置
  16. int q[N], hh = 0, tt = 0;
  17. // 向队尾插入一个数
  18. q[tt ++ ] = x;
  19. if (tt == N) tt = 0;
  20. // 从队头弹出一个数
  21. hh ++ ;
  22. if (hh == N) hh = 0;
  23. // 队头的值
  24. q[hh];
  25. // 判断队列是否为空
  26. if (hh != tt)
  27. {
  28. }

题目

小组队列

这题需要两组队列,一组队列用于维护各个小组,另外一组用于维护小组间的顺序
用哈希表存储每个人对应的小组序号
剩下的按照题意模拟即可

  1. #include <iostream>
  2. #include <queue>
  3. #include <unordered_map>
  4. #include <string>
  5. using namespace std;
  6. const int N = 1010;
  7. unordered_map<int, int> rec;
  8. int main() {
  9. int n, no = 1;
  10. while (cin >> n, n) {
  11. printf("Scenario #%d\n", no++);
  12. for (int i = 0; i < n; i++) {
  13. int cnt;
  14. scanf("%d", &cnt);
  15. for (int j = 0; j < cnt; j++) {
  16. int x;
  17. scanf("%d", &x);
  18. rec[x] = i; // 哈希:人对应的小组编号
  19. }
  20. }
  21. queue<int> team[N];
  22. queue<int> all;
  23. string op;
  24. while (cin >> op, op != "STOP") {
  25. if (op == "ENQUEUE") {
  26. int x;
  27. scanf("%d", &x);
  28. int tid = rec[x];
  29. if (team[tid].empty()) all.push(tid);
  30. team[tid].push(x);
  31. }
  32. else {
  33. int tid = all.front();
  34. int x = team[tid].front();
  35. team[tid].pop();
  36. printf("%d\n", x);
  37. if (team[tid].empty()) all.pop();
  38. }
  39. }
  40. putchar('\n');
  41. }
  42. return 0;
  43. }

蚯蚓

这题要求维护一个集合,支持查询最大值、删除最大值、插入新的值,可以考虑使用二叉堆
对于其余蚯蚓每个长度增加q,可以转化成新增蚯蚓的长度减去q,再用一个变量维护整个过程中长度增加总和
上面是常规做法,但是这题数据量大,要求每次操作是O(1)的,这就需要挖掘题目中的规律
简单说就是,如果我们按照长度从大到小取出数,新产生的数也会按照时间递减
这样一来只要用三个队列,每个从三个队头挑出最大的那个就行

  1. #include <iostream>
  2. #include <algorithm>
  3. #include <limits.h>
  4. using namespace std;
  5. typedef long long LL;
  6. const int N = 7e6 + 10;
  7. int a[N], l[N], r[N];
  8. int hha = 0, hhl = 0, hhr = 0, tta = -1, ttl = -1, ttr = -1;
  9. int n, m, q, u, v, t;
  10. int get_max() {
  11. int res = INT_MIN;
  12. if (tta >= hha) res = max(res, a[hha]);
  13. if (ttl >= hhl) res = max(res, l[hhl]);
  14. if (ttr >= hhr) res = max(res, r[hhr]);
  15. if (tta >= hha && res == a[hha]) hha++;
  16. else if (ttl >= hhl && res == l[hhl]) hhl++;
  17. else hhr++;
  18. return res;
  19. }
  20. int main() {
  21. // cin >> n >> m >> q >> u >> v >> t;
  22. scanf("%d%d%d%d%d%d", &n, &m, &q, &u, &v, &t);
  23. for (int i = 0; i < n; i++) {
  24. int x;
  25. scanf("%d", &x);
  26. a[++tta] = x;
  27. }
  28. sort(a, a + n);
  29. reverse(a, a + n);
  30. int delta = 0;
  31. for (int i = 1; i <= m; i++) {
  32. int x = get_max();
  33. x += delta;
  34. if (i % t == 0) printf("%d ", x);
  35. delta += q;
  36. int left = 1ll * x * u / v, right = x - left;
  37. l[++ttl] = left - delta, r[++ttr] = right - delta;
  38. }
  39. putchar('\n');
  40. for (int i = 1; i <= n + m; i++) {
  41. int x = get_max();
  42. if (i % t == 0) printf("%d ", x + delta);
  43. }
  44. return 0;
  45. }

双端队列

名叫双端队列但是关系不大的一道题
考虑这样一种情况,不幸将PQ放入同一个队列,后面出现介于PQ之间的数,直接完蛋
这启发我们从数值大小而非输入顺序去考虑
可以先把数组从小到大排序,然后根据原始下标分成尽量少的几段,每一段对应一个双端队列
双端队列对于数据的要求是满足单谷性质(先单减后单增),这样一来队列可以从中间向两边扩展(建议画图)
我们要做的就是根据原始下标大小找出最少的单谷数目
操作空间主要在于连续几个相等的数可以重新排序,这里采用贪心策略,尽量保持上一段的单调性

  1. #include <iostream>
  2. #include <algorithm>
  3. #include <limits.h>
  4. using namespace std;
  5. typedef pair<int, int> PII;
  6. const int N = 2e5 + 10;
  7. PII a[N];
  8. int main() {
  9. int n;
  10. cin >> n;
  11. for (int i = 1; i <= n; i++) {
  12. scanf("%d", &a[i].first);
  13. a[i].second = i;
  14. }
  15. sort(a + 1, a + n + 1);
  16. int last = INT_MAX, ans = 1, dir = -1;
  17. int i = 1;
  18. while (i <= n) {
  19. int j = i;
  20. while (a[++j].first == a[i].first);
  21. int minp = a[i].second, maxp = a[j - 1].second;
  22. if (dir == -1) {
  23. if (maxp < last) {
  24. last = minp;
  25. }
  26. else {
  27. dir = 1;
  28. last = maxp;
  29. }
  30. }
  31. else {
  32. if (minp > last) {
  33. last = maxp;
  34. }
  35. else {
  36. last = minp;
  37. dir = -1;
  38. ans++;
  39. }
  40. }
  41. i = j;
  42. }
  43. cout << ans;
  44. return 0;
  45. }