• P1886 P2216 单调队列模板


    何为单调队列?

    单调队列是一个队列(废话)

    而且必须同时满足下标单调和值单调两个单调特性。

    跟优先队列不同,优先队列直接使用堆(heap)来实现,如何删去特定下标元素?不明。

    本人喜欢用单调队列存下标,这样比存值不知道高到哪里去了。

    新来一个元素,进队。之后特判长度有没有超过。超过则把最前面的元素出队。

    之后,如果不满足性质,就把前面的元素顶掉,直到满足性质为止。

    然后才可以把队首元素拿来用。

    有几个很坑的地方,具体看代码注释。

    (为什么top是队尾而tail是队首?laughcry)

    例题:洛谷P1886,高级模板题。还有一道剧毒的P2216。(排版很奇怪,都怪反人类的博客园☺)

    AC代码:

     1 #include <cstdio>
     2 const int N = 1000010;
     3 
     4 int pl[N], l_t, l_h = 1, ansl[N];
     5 int ps[N], s_t, s_h = 1, anss[N];
     6 int a[N];
     7 
     8 int main() {
     9     int n, k;
    10     scanf("%d%d", &n, &k);
    11     for(int i = 1; i <= n; i++) {
    12         scanf("%d", &a[i]);
    13     }
    14     for(int i = 1; i <= n; i++) {
    15         pl[++l_t] = i;
    16         ps[++s_t] = i;
    17         if(pl[l_h] + k <= i) {
    18             l_h++;
    19         }
    20         if(ps[s_h] + k <= i) {
    21             s_h++;
    22         }
    23         while(l_t > l_h && a[pl[l_t - 1]] <= a[i]) {
    24             l_t--;
    25         }
    26         while(s_t > s_h && a[ps[s_t - 1]] >= a[i]) {
    27             s_t--;
    28         }
    29         pl[l_t] = i;
    30         ps[s_t] = i;
    31         ansl[i] = pl[l_h];
    32         anss[i] = ps[s_h];
    33     }
    34     for(int i = k; i <= n; i++) {
    35         printf("%d ", a[anss[i]]);
    36     }
    37     printf("
    ");
    38     for(int i = k; i <= n; i++) {
    39         printf("%d ", a[ansl[i]]);
    40     }
    41     return 0;
    42 }
    最新写的P1886
     1 #include <cstdio>
     2 #include <algorithm>
     3 using namespace std;
     4 const int N=1002;
     5 struct ah{int large,small;}f[N][N];
     6 int c[N][N];
     7 int p1[N],p2[N],top1,tail1=1,top2,tail2=1;///存下标
     8 int a,b,n;///p1求min,p2求max
     9 long long int ans=999999999,s;
    10 
    11 int main()
    12 {
    13     scanf ("%d%d%d",&a,&b,&n);
    14     for(int i=1;i<=a;i++)
    15     {
    16         top1=top2=0;
    17         tail1=tail2=1;
    18         for(int j=1;j<=b;j++)
    19         {
    20             scanf ("%d",&c[i][j]);
    21             p1[++top1]=p2[++top2]=j;
    22             while(c[i][p1[top1]]<=c[i][p1[top1-1]] && top1>tail1)
    23             {///单调队列维护
    24                 p1[top1-1]=p1[top1];
    25                 top1--;
    26             }
    27             while(c[i][p2[top2]]>=c[i][p2[top2-1]] && top2>tail2)
    28             {
    29                 p2[top2-1]=p2[top2];
    30                 top2--;
    31             }
    32             if(p1[top1]-p1[tail1]>=n) tail1++;///区间长度n
    33             if(p2[top2]-p2[tail2]>=n) tail2++;
    34             if(j>=n)
    35             {///产生最大最小值
    36                 f[i][j-n+1].large=c[i][p2[tail2]];
    37                 f[i][j-n+1].small=c[i][p1[tail1]];
    38             }
    39         }
    40     }
    41     ///读入完毕,处理①完毕
    42 /*
    43     for(int i=1;i<=a;i++)///调试
    44     {
    45         for(int j=1;j<=b-n+1;j++)
    46         {
    47             printf("%d-%d ",f[i][j].large,f[i][j].small);
    48         }
    49         printf("
    ");
    50     }*/
    51 
    52 
    53     for(int j=1;j<=b-n+1;j++)
    54     {
    55         top1=top2=0;
    56         tail1=tail2=1;
    57         for(int i=1;i<=a;i++)///p1 small  p2 large
    58         {
    59             p1[++top1]=p2[++top2]=i;
    60             while(f[p1[top1]][j].small<=f[p1[top1-1]][j].small && top1>tail1)
    61             {
    62                 p1[top1-1]=p1[top1];
    63                 top1--;
    64             }
    65             while(f[p2[top2]][j].large>=f[p2[top2-1]][j].large && top2>tail2)
    66             {
    67                 p2[top2-1]=p2[top2];
    68                 top2--;
    69             }
    70             if(p1[top1]-p1[tail1]>=n) tail1++;
    71             if(p2[top2]-p2[tail2]>=n) tail2++;
    72             if(i>=n)
    73             {///产生最值
    74                 s=1ll*(f[p2[tail2]][j].large-f[p1[tail1]][j].small);
    75                 //printf("%d ",s);
    76                 ans=min(ans,s);
    77             }
    78 
    79         }
    80         //printf("
    ");
    81     }
    82     printf("%lld",ans);
    83     return 0;
    84 }
    P2216

    博客园排版有剧毒。。。

  • 相关阅读:
    搭建kafka高级消费 (high-consumer)php7
    kafka搭建到配置borker集群(项目开发-区块链)
    快速提高谷歌浏览器(Chrome)自带下载器的网速
    利用IO和File类实现拷贝文件目录问题
    随机红包小算法
    二叉树前序中序后序层序遍历问题
    荷兰国旗问题
    二分法查找
    找出数组中最大值and索引
    数组元素反转
  • 原文地址:https://www.cnblogs.com/huyufeifei/p/8443027.html
Copyright © 2020-2023  润新知