有一个长为 n 的序列 a,以及一个大小为 k 的窗口。现在这个从左边开始向右滑动,每次滑动一个单位,求出每次滑动后窗口中的最大值和最小值。
例如,对于序列 [1,3,-1,-3,5,3,6,7] 以及 k = 3,有如下过程:
输入一共有两行,第一行有两个正整数 n,k。
第二行 n 个整数,表示序列 a
输出共两行,第一行为每次窗口滑动的最小值
第二行为每次窗口滑动的最大值
### 样例输入 #1
```
8 3
1 3 -1 -3 5 3 6 7
```
### 样例输出 #1
```
-1 -3 -3 -3 3 3
3 3 5 5 6 7
```
【数据范围】
对于 50% 的数据,1 <= n <= 10^5;
对于 100% 的数据,1<= k <= n <= 10^6,ai <=[-2^31,2^31)。
这道题不能直接用暴力的去搜索最大值,我也不建议去这样做,这道题主要是给我们介绍一个概念:单调队列。这种队列的特别之处在于它的队列之中的所有成员都是单调增加或减少的。
#include
using namespace std;
long long a[10000000];
long long b[10000000];
long long c[10000000];
long long l=1,r=0,l1=1,r1=0;
long long n,m,q=0,e=0;
long long b1[10000000];
long long c1[10000000];
int main()
{
long long x,y,z;
scanf("%lld%lld",&n,&m);
for(x=1;x<=n;x++)
{
scanf("%lld",&a[x]);
}
for(x=1;x<=n;x++)
{
while(l<=r&&a[b[r]]>=a[x])r--; //判断入列的位置
b[++r]=x; //入列
if(b[l]=m)
{
b1[q++]=b[l];
c1[e++]=c[l1];
}
}
for(x=0;x
杖刀偶磨弓是埴轮兵团的首长。
作为埴轮兵长,训练埴轮兵团是很平常的事情。
磨弓下达命令让埴轮们站成一行。不妨认为它们站在了一个数轴上,每个埴轮的位置就是它脚下数轴的数字。磨弓会告诉你,第 i 个埴轮的位置为 ai 。不保证 ai 升序。
数轴的长度是有限制的,具体的范围是 [-k,k] 。也就是说,如果某个埴轮移出了这个范围,它就脱离了这个队列了,并且不会再次回到队列当中。
为了训练埴轮,磨弓给埴轮们下达了 m 个指令,有以下 3 种:
- 指令 1:全体埴轮向数轴的正方向移动 x 个单位长度。
- 指令 2:全体埴轮往数轴的反方向移动 x 个单位长度。
- 指令 3:依次报数,统计目前队列里一共有多少个埴轮。
但是磨弓发现,埴轮兵团的大小实在是太大了,以至于执行这些操作变得非常缓慢。尽管如此,磨弓仍然希望你告诉她所有指令 3 的结果。
第一行共有 3 个整数 n, m, k,含义如题面所示。
第二行共有 n 个整数 a1, a2, ……, an,表示每个埴轮的位置。
接下来 m 行,有 1 或者 2 个正整数,描述一条指令。首先是一个整数 op,表示这条指令的类型。如果 1 <= op <= 2,接下来还会输入一个整数 x。
对于每条指令 3 ,输出一个整数,表示目前还在队列中的埴轮的数目。
### 样例输入 #1
```
3 4 3
-1 1 2
2 3
3
1 5
3
```
### 样例输出 #1
```
2
1
```
#### 样例 1 说明
一共有三个埴轮。初始时,它们的站位分别是 [-1,1,2] 。
- 第一次操作后,所有埴轮向左移动 3 格,位置变成了 [-4,-2,-1]。第一个埴轮被移出了数轴。
- 第二次操作后,输出当前的埴轮数目,为 2 个。
- 第三次操作后,所有埴轮向右移动 5 格,位置变成了 [3,4] ,第二个埴轮被移出了数轴。
- 第四次操作后,输出当前的埴轮数目,为 1 个。
#### 数据规模与约定
- 对于 30% 的数据,1 <= n, m <= 5* 10^3;
- 对于另外 20% 的数据,1<= k<= 500;
- 对于 100% 的数据,1 <= n, m <= 3* 10^5,1 <= k, x <= 2 * 10^9,-k <= ai <= k 。
用一个数组来记录这些埴轮的位置,然后一个个去模拟就行了,但是如果一个个去改变他的每一个的值的话会超时,因为每一个偏移量都是对整个数组的,就用一个变量来保存这个偏移量就行了。
#include
#include
using namespace std;
long long g[300002];
int main()
{
long long n,m,k,x,y,z=0,h;
long long l,r;
scanf("%lld%lld%lld",&n,&m,&k);
for(x=0;xk&&l<=r)r--; //把超出范围的数从双向队列里删除
}
if(y==2)
{
scanf("%lld",&h);
z-=h; //更改偏移量
while(g[l]+z<-k&&l<=r)l++; //把超出范围的数从双向队列里删除
}
if(y==3)
{
printf("%lld\n",r-l+1); //输出队列里剩余的数
}
}
return 0;
}