题意::::现在有一堆数字共N个数字(N<=10^6),以及一个大小为k的窗口。现在这个从左边开始向右滑动,每次滑动一个单位,求出每次滑动后窗口中的最大值和最小值。
解法 1)单调队列 2)线段树(n * log n)
单调队列分析::
考虑最小值情况::
以该样例为例子说明:::
8 3
1 3 -1 -3 5 3 6 7(在这里非常巧妙的就是用下标来维护窗口大小,保证均在合理范围内不越界)
q表示队列入队的为下标
1:队空 1 直接 入队 q={1}; 3 也直接入队 q={1,2};-1 则弹出前两项 q={3};
2: -3 则弹出前一项 q={4}; 5 直接入队 q={4,5}; 3 则弹出前一项 q={4,6};同时 队头下次操作越界 所以pop q={6};
3:6 直接入队 q={6,7}; 7 也直接入队 q={6,7,8};同时 队头下次操作越界 所以pop q={7,8};
1):当队列非空且队尾指向的下标元素小于当前或等于当前值---->不断弹出队尾
2):下标入队尾
3):判断队头所指向的下标是否越界,是则 pop
最大值情况同样考虑\
1 #include <bits/stdc++.h>
2 #define ll long long
3 const int maxn=1e6+5;
4 using namespace std;
5
6 int ma[maxn];
7 int a[maxn],b[maxn];
8 deque<int>q;
9 int main()
10 {
11 int n,k;
12 scanf("%d%d",&n,&k);
13 for(int i=1;i<=n;i++){
14 scanf("%d",&ma[i]);
15 }
16 //最小值
17 for(int i=1;i<=n;i++)
18 {
19 while(!q.empty()&&ma[q.back()]>=ma[i]){
20 q.pop_back();
21 }
22 q.push_back(i);
23 a[i]=ma[q.front()];
24 if(q.front()<=i-k+1&&i>=k){
25 q.pop_front();
26 }
27 }
28
29 while(!q.empty())
30 {
31 q.pop_back();
32 }
33 for(int i=1;i<=n;i++)
34 {
35 while(!q.empty()&&ma[q.back()]<=ma[i]){
36 q.pop_back();
37 }
38 q.push_back(i);
39 b[i]=ma[q.front()];
40 if(q.front()<=i-k+1&&i>=k){
41 q.pop_front();
42 }
43 }
44 for(int i=k;i<=n;i++){
45 printf("%d ",a[i]);
46 }
47 printf("\n");
48 for(int i=k;i<=n;i++){
49 printf("%d ",b[i]);
50 }
51 return 0;
52 }
线段树更容易理解就不解释了,贴代码 (AC 900+ms 时间看着很慌,数据好点估计会卡死)
1 #include<bits/stdc++.h>
2 #define ll long long
3 const int MOD=1e9+7;
4 using namespace std;
5 const int maxn=1e6+5;
6
7 int Min[4*maxn],a[maxn],Max[4*maxn];
8 int ma[maxn],mb[maxn];
9
10 void pushup(int rt)
11 {
12 Max[rt]=max(Max[2*rt],Max[2*rt+1]);
13 Min[rt]=min(Min[2*rt],Min[2*rt+1]);
14 }
15 void build(int l,int r,int rt)
16 {
17 if(l==r){
18 Max[rt]=a[l];
19 Min[rt]=a[l];
20 return ;
21 }
22 int mid=(l+r)>>1;
23 build(l,mid,2*rt);
24 build(mid+1,r,2*rt+1);
25 pushup(rt);
26 }
27
28 int query1(int L,int R,int l,int r,int rt)
29 {
30 if(L<=l&&R>=r){
31 return Max[rt];
32 }
33 int mid=(l+r)>>1;
34 int ans=-1e9;
35 if(L<=mid){
36 ans=max(ans,query1(L,R,l,mid,2*rt));
37 }
38 if(R>mid){
39 ans=max(ans,query1(L,R,mid+1,r,2*rt+1));
40 }
41 return ans;
42 }
43 int query2(int L,int R,int l,int r,int rt)
44 {
45 if(L<=l&&R>=r){
46 return Min[rt];
47 }
48 int mid=(l+r)>>1;
49 int ans=1e9;
50 if(L<=mid){
51 ans=min(ans,query2(L,R,l,mid,2*rt));
52 }
53 if(R>mid){
54 ans=min(ans,query2(L,R,mid+1,r,2*rt+1));
55 }
56 return ans;
57 }
58 int main()
59 {
60 int n,m;
61 scanf("%d%d",&n,&m);
62 for(int i=1;i<=n;i++){
63 scanf("%d",&a[i]);
64 }
65 build(1,n,1);
66 for(int i=1;i<=n-m+1;i++)
67 {
68 ma[i]=query2(i,i+m-1,1,n,1);
69 mb[i]=query1(i,i+m-1,1,n,1);
70 }
71 for(int i=1;i<=n-m+1;i++){
72 printf("%d ",ma[i]);
73 }
74 printf("\n");
75 for(int i=1;i<=n-m+1;i++){
76 printf("%d ",mb[i]);
77 }
78 return 0;
79 }