我偏要用STL!
这道题标签里给了线段树,单调队列等等多种解法。似乎很少使用STL的,用的比较多的也是deque,那么我来写一份利用另外一种结构定义的数据结构AC这道题的题解。
思路:
头指针指向i,尾指针指向i+k-1,先将1-k中的数字压入容器,求出两个最值,最小值当场输出,最大值存入数组。每次删去头指针指向的数,并执行i++,将新的尾指针指向的数压入容器,求最值,如上反复(对此不太理解的同学可以看一看“尺取法”)
注意:目前系列赛中多数已经允许使用O2优化,而使用O2优化一般情况下是STL能够被应用的基本条件之一。
数据结构:multiset
定义方式:
multiset<int,less<int> > q1;
- 建立一个内部元素升序排列的multiset容器
multiset的容器定义于set内。但是multiset与set相比具有以下优点:
- set中不能存储相同的元素,但是multiset可以。
- multiset可以同时删除所有相同元素,也可以利用迭代器删除某一个位置的元素
相比于手写的单调队列,multiset有如下的优点:
- 编程复杂度低,不需要实现复杂的过程,multiset自带insert(),find(),erase()等等好用的成员函数,不需要亲自实现
- 在开启O2优化的情况下,multiset的运行速度并不比手动实现的数据结构要慢(multiset内部利用红黑树实现自我平衡,保证数据有序)
下面介绍几个需要用到的成员函数:
s.begin():返回一个指向容器头部的迭代器
- 可以通过*s.begin()来取值。
s.end():返回一个指向容器尾部的迭代器
- 可以通过*s.end()来取值。
- 注意:s.end()存储的是一个被擦除的垃圾值,因此,真正的最大值在end的前一个迭代器内。我们可以将s.end()赋值给一个迭代器it,通过it–来实现.其中,it应该这样定义:
multiset<int>::iterator it;
s.find(int x):返回一个指向容器中第一个值为x的元素的迭代器
s.erase(iterator it):删除迭代器it指向的元素
- 特别注明:erase中间如果传入整数x,那么会删除所有与x相同的元素,而本题每次删除一个,所以利用find和erase配合。
s.insert(int x):在容器中插入一个值为x的元素
注意细节:
- 输出时iterator必须使用*取值,因为iterator实际上就是一种复杂而特殊的指针
- 必须将s.end()赋值给it后再执行it–,然后输出*it,因为直接执行–s.end()可能会导致一些难以挽回的错误
- 为什么要先存储max值最后输出呢?为什么不能用两个multiset分别存储呢?因为这样可以节省空间和时间,在本题最大的测试点#9中,我的程序运行了980ms,消耗了28MB的空间。如果重新跑一遍取最大值肯定TLE(不要问我怎么知道的,看我记录就知道我TLE了多少次)
想TLE就尽管不用读入优化
代码实现:我知道你们最喜欢这个了
// luogu-judger-enable-o2
#include<bits/stdc++.h>
using namespace std;
multiset <int,less<int> > q1;
inline int read(){
int x=0,k=1; char c=getchar();
while(c<'0'||c>'9'){if(c=='-')k=-1;c=getchar();}
while(c>='0'&&c<='9')x=(x<<3)+(x<<1)+(c^48),c=getchar();
return x*k;
}
int n,m;
int dat[1001000];
int getmax[1001000];
int main()
{
n=read();
m=read();
for(int i=1;i<=n;i++)
{
dat[i]=read();
}
for(int i=1;i<=m;i++)
{
q1.insert(dat[i]);
}
printf("%d ",*q1.begin());
int j=1;
multiset<int>::iterator it=q1.end();
it--;
getmax[j]=*it;
for(int i=m+1;i<=n;i++)
{
q1.insert(dat[i]);
q1.erase(q1.find(dat[i-m]));
printf("%d ",*q1.begin());
it=q1.end();
it--;
getmax[++j]=*(it);
}
printf("\n");
for(int i=1;i<=j;i++)
{
printf("%d ",getmax[i]);
}
printf("\n");
return 0;
}