• 《算法竞赛进阶指南》 双端队列


    达达现在碰到了一个棘手的问题,有 NN 个整数需要排序。

    达达手头能用的工具就是若干个双端队列。

    她从 11 到 NN 需要依次处理这 NN 个数,对于每个数,达达能做以下两件事:

    1.新建一个双端队列,并将当前数作为这个队列中的唯一的数;

    2.将当前数放入已有的队列的头之前或者尾之后。

    对所有的数处理完成之后,达达将这些队列按一定的顺序连接起来后就可以得到一个非降的序列。

    请你求出最少需要多少个双端序列。

    输入格式

    第一行输入整数 NN,代表整数的个数。

    接下来 NN 行,每行包括一个整数 DiDi,代表所需处理的整数。

    输出格式

    输出一个整数,代表最少需要的双端队列数。

    数据范围

    1≤N≤2000001≤N≤200000

    输入样例:

    1. 6
    2. 3
    3. 6
    4. 0
    5. 9
    6. 6
    7. 3

    输出样例:

    2

     此题解借鉴于acwing的大佬:AcWing 134. 双端队列 - AcWing

     

    解题代码

     

    1. /*
    2. * Project: 0x12_Queue
    3. * File Created:Friday, January 1st 2021, 13:31:39 pm
    4. * Author: Bug-Free
    5. * Problem:AcWing 134. 双端队列
    6. */
    7. #include <algorithm>
    8. #include <iostream>
    9. using namespace std;
    10. const int N = 2e5 + 10;
    11. typedef pair<int, int> PII;
    12. #define value first
    13. #define before_sort second
    14. PII a[N];
    15. int n;
    16. int main() {
    17. cin >> n;
    18. for (int i = 0; i < n; i++) {
    19. cin >> a[i].value;
    20. a[i].before_sort = i;
    21. }
    22. sort(a, a + n);
    23. int res = 1; // 最后最少分成的段数
    24. // last记录一下上一个值(上一段的最后一个值是多少),
    25. // 初始化为比所有坐标都大即可(>n的数字均可) dir用来记录方向
    26. // 第一条边一定是下降的, 因此dir初始化为-1(可以理解为是从上面接下来的)
    27. for (int i = 0, last = n + 1, dir = -1; i < n;) {
    28. int j = i + 1;
    29. // 找到一段相等的数值
    30. // 如果这一段的数字是相等的, 那么这些下标是可以随意变换的
    31. // 从i-j-1这一段, 都是和a[i].value相同的数字
    32. while (j < n && a[j].value == a[i].value) {
    33. j++;
    34. }
    35. // 找到这一段中的最大的下标和最小的下标
    36. // 因为是sort(pair经过sort)过的, 因此minx一定这一段的第一个数的位置
    37. // maxx一定是这一段的最后一个数的位置
    38. // 在原序列中的的位置
    39. // minx=a[i].before_sort, maax = a[j-1].before_sort;
    40. // 我们处理的时候是一个点一个点进行处理的(如果有相同的, 则处理一段,
    41. // 因为相同的可以任意插入到一个双端队列)
    42. int minx = a[i].before_sort, maxx = a[j - 1].before_sort;
    43. if (dir == -1) { //如果是下降的, 如何做?
    44. if (last > maxx) { //如果上一个位置>当前的最大位置,
    45. //那么就可以接到上一个位置的后面
    46. last =
    47. minx; // 接上了的话, 这一段的最后一个数值(原坐标)应该是minx
    48. } else { //如果没有接上, 那么更新方向为上升, last=maxx
    49. // 此时不需要res++的原因是 谷是先下降, 后上升的
    50. // 上升结束之后, 才需要开启新的谷
    51. dir = 1, last = maxx; // 上升的时候last更新为最大值,
    52. }
    53. } else { // 如果是上升的, 如何做?
    54. if (last <
    55. minx) { // 如果last比我当前这一段的最小值还要小, 那么可以接上去
    56. last = maxx;
    57. } else { // 否则开新双端队列+更新last为这一段的最小值,
    58. // 更新方向为下降
    59. res++;
    60. last = minx;
    61. dir = -1;
    62. }
    63. }
    64. i = j;
    65. }
    66. cout << res << endl;
    67. return 0;
    68. }

     作者:个人空间 - AcWing

  • 相关阅读:
    ABP +VUE Elment 通用高级查询(右键菜单)设计+LINQ通用类Expression<Func<TFields, bool>>方法
    cnpm安装步骤
    Arcgis 10.2.2 | arcgis license server无法启动的解决办法
    HelloSpring
    Paas 相关介绍
    温振传感器有几种传输方式?
    中国冰淇淋市场深度评估及发展趋势预测报告(2022版)
    MyBatis概述
    分布式微服务架构-一起学习吧之架构
    使用 frp 实现 windows 远程
  • 原文地址:https://blog.csdn.net/qq_61935738/article/details/125613578