当前位置:   article > 正文

洛谷 - P1886 滑动窗口(单调队列/线段树)_洛谷1886

洛谷1886

题目链接:点击查看

题目大意:给出一个由n个数构成的序列,再给出一个长度为k的窗口,这个窗口从第一个下标开始一直向后移动,每次移动一个单位,每次移动询问一次该窗口中的最大值和最小值,最后输出答案

题目分析:看似是一个模拟,其实暴力模拟肯定会爆,因为涉及到区间最值问题,而且还是静态的询问,所以这个题目有三种方法可以解决,分别是st表,线段树和单调队列,因为st表我不会优化,所以有五个测试点MLE了,这里就不用那个方法了,线段树的话空间复杂度比起st表一般是能小上5倍左右,但时间复杂度每一次查询时要多logn的常数,所以酌情考虑吧,用线段树的话就不会MLE了,擦边把这个题目给A了,一会也放一下代码,没什么好说的,主要是来说一下单调队列来做这个题目,之前只是学过单调栈,今天接触了一下单调队列,发现还是挺简单的,主要原理就是用双端队列维护一个严格递增或严格递减的序列,每次增加一个新值的时候,将其与尾部比较,最终插入尾部,当使用的时候,是使用头部的数值,大概就是这样了,一会看代码理解一下吧

然后这个题目还需要维护一下每个数值所代表的id,用来判断该数值在当前区间中是否过期,若过期的话直接舍弃掉即可

当然三种方法的复杂度来比较一下吧:

st表:空间复杂度nlogn,时间复杂度:打表nlogn,查询O(1)

线段树:空间复杂度n*4,时间复杂度:建树nlogn,查询nlogn

单调队列:空间复杂度n,时间复杂度:n

吐槽一句:这个题目本来是poj上的题目,为什么跑来洛谷做呢,三种方法,st表MLE,线段树TLE,单调队列还不支持C++11,我:????

代码:

单调队列(deque):

  1. #include<iostream>
  2. #include<cstdlib>
  3. #include<string>
  4. #include<cstring>
  5. #include<cstdio>
  6. #include<algorithm>
  7. #include<climits>
  8. #include<cmath>
  9. #include<cctype>
  10. #include<stack>
  11. #include<queue>
  12. #include<list>
  13. #include<vector>
  14. #include<set>
  15. #include<map>
  16. #include<sstream>
  17. #include<deque>
  18. using namespace std;
  19. typedef long long LL;
  20. const int inf=0x3f3f3f3f;
  21. const int N=1e6+100;
  22. struct Node
  23. {
  24. int val,id;
  25. }a[N];
  26. int ans_max[N],ans_min[N];
  27. int main()
  28. {
  29. // freopen("input.txt","r",stdin);
  30. // ios::sync_with_stdio(false);
  31. int n,k;
  32. while(scanf("%d%d",&n,&k)!=EOF)
  33. {
  34. for(int i=1;i<=n;i++)
  35. {
  36. scanf("%d",&a[i].val);
  37. a[i].id=i;
  38. }
  39. deque<Node>mmax;//维护最大值的单调队列
  40. deque<Node>mmin;//维护最小值的单调队列
  41. for(int i=1;i<=k-1;i++)//预处理1~k-1的值
  42. {
  43. while(mmax.size()&&mmax.back().val<=a[i].val)//将比当前值小的数全删掉(尾部)
  44. mmax.pop_back();
  45. mmax.push_back(a[i]);
  46. while(mmin.size()&&mmin.back().val>=a[i].val)//将比当前值大的数全删掉(尾部)
  47. mmin.pop_back();
  48. mmin.push_back(a[i]);
  49. }
  50. for(int i=k;i<=n;i++)//枚举滑动窗口的末尾位置
  51. {
  52. int left=i-k+1;//记录滑动窗口的首位置
  53. while(mmax.size()&&mmax.back().val<=a[i].val)//将比当前值小的数全删掉(尾部)
  54. mmax.pop_back();
  55. mmax.push_back(a[i]);
  56. while(mmin.size()&&mmin.back().val>=a[i].val)//将比当前值大的数全删掉(尾部)
  57. mmin.pop_back();
  58. mmin.push_back(a[i]);
  59. while(mmax.size()&&mmax.front().id<left)//将过期的值删掉(头部)
  60. mmax.pop_front();
  61. while(mmin.size()&&mmin.front().id<left)//将过期的值删掉(头部)
  62. mmin.pop_front();
  63. ans_max[left]=mmax.front().val;//更新答案
  64. ans_min[left]=mmin.front().val;
  65. }
  66. printf("%d",ans_min[1]);
  67. for(int i=2;i+k-1<=n;i++)
  68. printf(" %d",ans_min[i]);
  69. printf("\n%d",ans_max[1]);
  70. for(int i=2;i+k-1<=n;i++)
  71. printf(" %d",ans_max[i]);
  72. printf("\n");
  73. }
  74. return 0;
  75. }

单调队列(模拟):专门给poj2823改的代码

  1. #include<iostream>
  2. #include<cstdlib>
  3. #include<string>
  4. #include<cstring>
  5. #include<cstdio>
  6. #include<algorithm>
  7. #include<climits>
  8. #include<cmath>
  9. #include<cctype>
  10. #include<stack>
  11. #include<list>
  12. #include<vector>
  13. #include<set>
  14. #include<map>
  15. #include<sstream>
  16. using namespace std;
  17. typedef long long LL;
  18. const int inf=0x3f3f3f3f;
  19. const int N=1e6+100;
  20. struct Node
  21. {
  22. int val,id;
  23. }t[N];
  24. int a[N];
  25. int main()
  26. {
  27. // freopen("input.txt","r",stdin);
  28. // ios::sync_with_stdio(false);
  29. int n,k;
  30. while(scanf("%d%d",&n,&k)!=EOF)
  31. {
  32. for(int i=1;i<=n;i++)
  33. scanf("%d",a+i);
  34. int l=1,r=0;
  35. for(int i=1;i<=n;i++)
  36. {
  37. int left=i-k+1;
  38. while(l<=r&&t[l].id<left)
  39. l++;
  40. while(l<=r&&t[r].val>=a[i])
  41. r--;
  42. t[++r].val=a[i];
  43. t[r].id=i;
  44. if(i>=k)
  45. printf("%d ",t[l].val);
  46. }
  47. printf("\n");
  48. l=1,r=0;
  49. for(int i=1;i<=n;i++)
  50. {
  51. int left=i-k+1;
  52. while(l<=r&&t[l].id<left)
  53. l++;
  54. while(l<=r&&t[r].val<=a[i])
  55. r--;
  56. t[++r].val=a[i];
  57. t[r].id=i;
  58. if(i>=k)
  59. printf("%d ",t[l].val);
  60. }
  61. printf("\n");
  62. }
  63. return 0;
  64. }

线段树:

  1. #include<iostream>
  2. #include<cstdlib>
  3. #include<string>
  4. #include<cstring>
  5. #include<cstdio>
  6. #include<algorithm>
  7. #include<climits>
  8. #include<cmath>
  9. #include<cctype>
  10. #include<stack>
  11. #include<queue>
  12. #include<list>
  13. #include<vector>
  14. #include<set>
  15. #include<map>
  16. #include<sstream>
  17. using namespace std;
  18. typedef long long LL;
  19. const int inf=0x3f3f3f3f;
  20. const int N=1e6+100;
  21. int ans1[N],ans2[N];
  22. struct Node
  23. {
  24. int l,r,mmax,mmin;
  25. }tree[N<<2];
  26. void build(int k,int l,int r)
  27. {
  28. tree[k].l=l;
  29. tree[k].r=r;
  30. if(l==r)
  31. {
  32. scanf("%d",&tree[k].mmin);
  33. tree[k].mmax=tree[k].mmin;
  34. return;
  35. }
  36. int mid=l+r>>1;
  37. build(k<<1,l,mid);
  38. build(k<<1|1,mid+1,r);
  39. tree[k].mmax=max(tree[k<<1].mmax,tree[k<<1|1].mmax);
  40. tree[k].mmin=min(tree[k<<1].mmin,tree[k<<1|1].mmin);
  41. }
  42. int query_max(int k,int l,int r)
  43. {
  44. if(tree[k].r<l||tree[k].l>r)
  45. return -inf;
  46. if(tree[k].r<=r&&tree[k].l>=l)
  47. return tree[k].mmax;
  48. return max(query_max(k<<1,l,r),query_max(k<<1|1,l,r));
  49. }
  50. int query_min(int k,int l,int r)
  51. {
  52. if(tree[k].r<l||tree[k].l>r)
  53. return inf;
  54. if(tree[k].r<=r&&tree[k].l>=l)
  55. return tree[k].mmin;
  56. return min(query_min(k<<1,l,r),query_min(k<<1|1,l,r));
  57. }
  58. int main()
  59. {
  60. // freopen("input.txt","r",stdin);
  61. // ios::sync_with_stdio(false);
  62. int n,k;
  63. while(scanf("%d%d",&n,&k)!=EOF)
  64. {
  65. build(1,1,n);
  66. for(int i=1;i+k-1<=n;i++)
  67. {
  68. ans1[i]=query_min(1,i,i+k-1);
  69. ans2[i]=query_max(1,i,i+k-1);
  70. }
  71. printf("%d",ans1[1]);
  72. for(int i=2;i+k-1<=n;i++)
  73. printf(" %d",ans1[i]);
  74. printf("\n%d",ans2[1]);
  75. for(int i=2;i+k-1<=n;i++)
  76. printf(" %d",ans2[i]);
  77. printf("\n");
  78. }
  79. return 0;
  80. }

 

声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:【wpsshop博客】
推荐阅读
相关标签
  

闽ICP备14008679号