目录
单调队列存储的是一段区间的单调递增或递减的子序列的下标值(为什么是下标值后面会说);因此取区间最值只取队头即可做到;
存储下标是为了方便将不属于本区间的队头去掉;利用q[hh]<i-m+1,hh++;
注意,队列是这样的,hh,。。。,tt;左边是队头,右边是队尾;
1,滑动窗口;
单调队列模板题,核心代码给出了注释;
int n,k;
int a[N];
int q[N],hh,tt=-1;
signed main()
{
quick_cin();
cin>>n>>k;
rep2(i,1,n)cin>>a[i];
rep2(i,1,n)
{
while(hh<=tt&&q[hh]<i-k+1)hh++;//不属于本区间的队头弹出;
while(hh<=tt&&a[i]<=a[q[tt]])tt--;//新进来的元素比队列里的元素还小,那么队列里的元素不可能是区间最小值,直接从队尾抛弃;
q[++tt]=i;//新进来的元素进入 队列;
if(i>=k)cout<<a[q[hh]]<<" ";
}
hh=0,tt=-1;
memset(q,0,q);
cout<<endl;
//同上;
rep2(i,1,n)
{
while(hh<=tt&&q[hh]<i-k+1)hh++;
while(hh<=tt&&a[i]>=a[q[tt]])tt--;
q[++tt]=i;
if(i>=k)cout<<a[q[hh]]<<" ";
}
return 0;
}
#pragma GCC optimize(2)
#include<bits/stdc++.h>
#define rep1(i,a,n) for(register int i=(a);i<(n);++i)
#define rep2(i,a,n) for(register int i=(a);i<=(n);++i)
#define per1(i,n,a) for(register int i=(n);i>(a);i--)
#define per2(i,n,a) for(register int i=(n);i>=(a);i--)
#define quick_cin() cin.tie(0),cout.tie(0),ios::sync_with_stdio(false)
#define memset(a,i,b) memset((a),(i),sizeof (b))
#define memcpy(a,i,b) memcpy((a),(i),sizeof (b))
#define pro_q priority_queue
#define pb push_back
#define pf push_front
#define endl "\n"
#define lowbit(m) ((-m)&(m))
#define YES cout<<"YES\n"
#define NO cout<<"NO\n"
#define Yes cout<<"Yes\n"
#define No cout<<"No\n"
#define yes cout<<"yes\n"
#define no cout<<"no\n"
#define yi first
#define er second
#define INF 0x3f3f3f3f
#define tulun int e[N],ne[N],h[N],w[N],idx;
#define add2(a,b) e[idx]=b,ne[idx]=h[a],h[a]=idx++;
#define add3(a,b,c) w[idx]=c,e[idx]=b,ne[idx]=h[a],h[a]=idx++;
#define T_solve() int T;cin>>T;while(T--)solve();
using namespace std;
typedef long long LL;
typedef pair<int,int> PII;
typedef pair<pair<int,int>,pair<int,int>> PIIII;
typedef double dob;
const int N=1e6+10;
int n,k;
int a[N];
int q[N],hh,tt=-1;
signed main()
{
quick_cin();
cin>>n>>k;
rep2(i,1,n)cin>>a[i];
rep2(i,1,n)
{
while(hh<=tt&&q[hh]<i-k+1)hh++;
while(hh<=tt&&a[i]<=a[q[tt]])tt--;
q[++tt]=i;
if(i>=k)cout<<a[q[hh]]<<" ";
}
hh=0,tt=-1;
memset(q,0,q);
cout<<endl;
rep2(i,1,n)
{
while(hh<=tt&&q[hh]<i-k+1)hh++;
while(hh<=tt&&a[i]>=a[q[tt]])tt--;
q[++tt]=i;
if(i>=k)cout<<a[q[hh]]<<" ";
}
return 0;
}
2,印刷广告;
思路:求出每个数向左和向右能拓展的最长长度;
维护一个单调递增的队列,每次都从队尾弹出到第一个小于当前高度的数,这样取到的下标是极限长度;
这里我用了q[-1]=0这个特点,这样就可以使队伍为空时,即它可以拓展到数组的最边界也能成立;(但会导致不能使用倒循环来求拓展右边界,因为q[0]=n,所以在我reverse h后才求对;后续会改善代码);
3,理想的正方形(二维滑动窗口模型);
题意:
思路:
我们先求出在行中,每个长度为n的长方形的最值,并存储到最右边的端点;
大概就是这样,第一行中,每个红色的点存储的就是它左边3个长度的最值;
那我求一个3*3的正方形的最值的时候,其实也就是对列方向上这个存储最值的三个长度的矩形取个最值;如图所示;
因此,就可以把二维的问题转化为两次一维的问题,先横着求一边行的最值, 在纵着对列求一遍最值;两次操作处理完后,正方形的最值就储存在它的右下角;遍历所有右下角即可得到最大值减去最小值;
#pragma GCC optimize(2)
#include<bits/stdc++.h>
#define rep1(i,a,n) for(register int i=(a);i<(n);++i)
#define rep2(i,a,n) for(register int i=(a);i<=(n);++i)
#define per1(i,n,a) for(register int i=(n);i>(a);i--)
#define per2(i,n,a) for(register int i=(n);i>=(a);i--)
#define quick_cin() cin.tie(0),cout.tie(0),ios::sync_with_stdio(false)
#define memset(a,i,b) memset((a),(i),sizeof (b))
#define memcpy(a,i,b) memcpy((a),(i),sizeof (b))
#define pro_q priority_queue
#define pb push_back
#define pf push_front
#define endl "\n"
#define lowbit(m) ((-m)&(m))
#define YES cout<<"YES\n"
#define NO cout<<"NO\n"
#define Yes cout<<"Yes\n"
#define No cout<<"No\n"
#define yes cout<<"yes\n"
#define no cout<<"no\n"
#define yi first
#define er second
#define INF 0x3f3f3f3f
#define tulun int e[N],ne[N],h[N],w[N],idx;
#define add2(a,b) e[idx]=b,ne[idx]=h[a],h[a]=idx++;
#define add3(a,b,c) w[idx]=c,e[idx]=b,ne[idx]=h[a],h[a]=idx++;
#define T_solve() int T;cin>>T;while(T--)solve();
using namespace std;
typedef long long LL;
typedef pair<int,int> PII;
typedef double dob;
const int N=1e3+10;
int row_min[N][N],row_max[N][N];
int n,m,k;
int w[N][N];
int q[N];
void get_min(int a[],int b[],int tot)
{
int hh=0,tt=-1;
rep2(i,1,tot)
{
while(hh<=tt&&q[hh]<=i-k)hh++;
while(hh<=tt&&a[i]<=a[q[tt]])tt--;
q[++tt]=i;
b[i]=a[q[hh]];
}
}
void get_max(int a[],int b[],int tot)
{
int hh=0,tt=-1;
rep2(i,1,tot)
{
while(hh<=tt&&q[hh]<=i-k)hh++;
while(hh<=tt&&a[i]>=a[q[tt]])tt--;
q[++tt]=i;
b[i]=a[q[hh]];
}
}
int ans[N],col_min[N],col_max[N];
PII zuizhi[N][N];
signed main()
{
quick_cin();
cin>>n>>m>>k;
rep2(i,1,n)
rep2(j,1,m)cin>>w[i][j];
rep2(i,1,n)
{
get_min(w[i],row_min[i],m);
get_max(w[i],row_max[i],m);
}
rep2(j,k,m)
{
rep2(i,1,n)ans[i]=row_min[i][j];
get_min(ans,col_min,n);
rep2(i,1,n)ans[i]=row_max[i][j];
get_max(ans,col_max,n);
rep2(i,1,n)zuizhi[i][j]={col_max[i],col_min[i]};
}
int res=INT_MAX;
rep2(i,k,n)
rep2(j,k,m)
res=min(res,zuizhi[i][j].first-zuizhi[i][j].second);
cout<<res;
return 0;
}