单调队列
一句话题意:给一个长为 \(n\) 的序列,有一长为k的滑动窗口,从左往右滑,问每次窗口内的最大值。 \((1 \le n \le 2 \times 10^6\))
单调队列:一种队列,用于求递增区间 \(min, max\) 。具体来说,对定长区间求 \(max\) ,每加入一个点,先将队列中不符合区间长度要求的弹出,再判断,弹出所有权值比当前元素更小的点,再插入当前元素。这样做会使队列中保持单调递减,于是队头一定是最大值。
#include<bits/stdc++.h>
using namespace std;
const int N = 2e6 + 10;
int n, len, a[N];
int q[N], hd = 1, tl;
int main()
{
scanf("%d%d", &n, &len);
for(int i = 1; i <= n; ++i) scanf("%d", &a[i]);
for(int i = 1; i <= n; ++i){
while(hd <= tl && q[hd] < i - len + 1) ++hd;//催命官
while(hd <= tl && a[q[tl]] < a[i]) --tl;//街头霸王
q[++tl] = i;
if(i >= len) cout << a[q[hd]] <<'\n';
}
return 0;
}#include<bits/stdc++.h>
using namespace std;
const int N = 1e3 + 5;
bool mp[N][N];
int l[N][N], r[N][N], h[N][N];
int stk[N], top;
int n, m;
long long res;
char v;
inline int read()
{
int x = 0;
while(!isdigit(v)) v = getchar();
while(isdigit(v)) x = (x << 1) + (x << 3) + v - 48, v = getchar();
return x;
}
int main()
{
n = read(); m = read();
for(int i = 1; i <= n; ++i)
for(int j = 1 ; j <= m; ++j)
{
while((v ^ '*') && (v ^ '.')) v = getchar();
mp[i][j] = (v ^ '*') ? true : false;
v = getchar();
}
for(int i = 1; i <= n; ++i)
for(int j = 1; j <= m; ++j)
if(mp[i][j])
h[i][j] = h[i - 1][j] + 1;
for(int i = 1; i <= n; ++i)
{
top = 0;
for(int j = m; j; --j)
{
while(top && h[i][j] <= h[i][stk[top]])
{
l[i][stk[top]] = j;
--top;
}
stk[++top] = j;
}
while(top)
{
l[i][stk[top]] = 0;
--top;
}
}
for(int i = 1; i <= n; ++i)
{
top = 0;
for(int j = 1; j <= m; ++j)
{
while(top && h[i][j] < h[i][stk[top]])
{
r[i][stk[top]] = j;
--top;
}
stk[++top] = j;
}
while(top)
{
r[i][stk[top]] = m + 1;
--top;
}
}
for(int i = 1; i <= n; ++i)
for(int j = 1; j <= m; ++j)
res += h[i][j] * (j - l[i][j]) * (r[i][j] - j);
cout << res;
return 0;
}

浙公网安备 33010602011771号