单调队列 BZOJ1342 BZOJ1047

先来个简单的
BZOJ1342 Sound静音问题https://www.lydsy.com/JudgeOnline/problem.php?id=1342

image.png

注意理解:
用单调增加的队列维护最小值
i 从1到 n 枚举,每一个 a[i] 都会加入队列,但 a[i] 加入队列前会重复在队尾比 a[i] 大的元素删除,也就是说,比 a[i] 小的元素一定是安全的。而该队列单增,则最小值一定是队首元素。当队首元素不在当前区间时,删除队首元素后,新的队首元素一定是当前区间的最小值。
用单调减小的队列维护最大值
同理。

#include<bits/stdc++.h>
using namespace std; 
static const int Maxn = 1000010;
int a[Maxn], q1[Maxn], q2[Maxn], id1[Maxn], id2[Maxn];
int main()
{
    int n, m, c, l1, l2, r1, r2, flag = 0;
    //cin >> n >> m >> c;
    scanf("%d%d%d", &n, &m, &c); 
    for(int i = 1; i <= n; i++) cin >> a[i];
    l1 = l2 = 1;
    r1 = r2 = 0;
    for(int i = 1; i <= n; i++){
        while(l1 <= r1 && i - id1[l1] >= m) l1++;
        while(l2 <= r2 && i - id2[l2] >= m) l2++;
        while(l1 <= r1 && a[i] <= q1[r1]) r1--;
        while(l2 <= r2 && a[i] >= q2[r2]) r2--; 
        q1[++r1] = q2[++r2] = a[i];
        id1[r1] = id2[r2] = i;
        if(i >= m && q2[l2] - q1[l1] <= c){
            //cout << i - m + 1 << endl; 
            printf("%d\n", i - m + 1);
            flag = 1;
        } 
    }
    if(!flag) printf("NONE");//cout << "NONE" << endl;
    return 0;
}

居然会卡cin和cout???长见识了

单调队列升级版

BZOJ1047 理想的正方形 https://www.lydsy.com/JudgeOnline/problem.php?id=1047
这道题其实也就是用好多好多单调队列。。。
先用单调队列找到每一行(记为h)从位置 i 开始的n个元素中的最大值和最小值,记为 Max[h][i] 和 Min[h][i];
然后用单调队列找到每一列(记为k)区间n内Max[i][k]的最大值和Min[i][k]的最小值,用二者之差来更新ans。

#include<bits/stdc++.h>
using namespace std;
int M[1010][1010], Max[1010][1010], Min[1010][1010];
int q1[1010], q2[1010], id1[1010], id2[1010];//q1递增单调队列,维护Min 
int main(){
    int a, b, n, l1, l2, r1, r2, ans =2e9;
    cin >> a >> b >> n;
    for(int i = 1; i <= a; i++)
        for(int j = 1; j <= b; j++) scanf("%d", &M[i][j]);
    for(int h = 1; h <= a; h++){
        memset(q1, 0, sizeof(q1));
        memset(q2, 0, sizeof(q2));
        memset(id1, 0, sizeof(id1));
        memset(id2, 0, sizeof(id2));
        l1 = l2 = 1, r1 = r2 = 0;
        for(int i = 1; i <= b; i++){
            while(l1 <= r1 && i - id1[l1] >= n) l1++;
            while(l2 <= r2 && i - id2[l2] >= n) l2++;
            while(l1 <= r1 && q1[r1] >= M[h][i]) r1--;
            while(l2 <= r2 && q2[r2] <= M[h][i]) r2--;
            id1[++r1] = id2[++r2] = i;
            q1[r1] = q2[r2] = M[h][i]; 
            if(i >= n){
                Max[h][i - n + 1] = q2[l2];
                Min[h][i - n + 1] = q1[l1];
            }
        }
    }
    for(int k = 1; k <= b - n + 1; k++){
        memset(q1, 0, sizeof(q1));
        memset(q2, 0, sizeof(q2));
        memset(id1, 0, sizeof(id1));
        memset(id2, 0, sizeof(id2));    
        l1 = l2 = 1; r1 = r2 = 0;
        for(int i = 1; i <= a; i++){
            while(l1 <= r1 && i - id1[l1] >= n) l1++;
            while(l2 <= r2 && i - id2[l2] >= n) l2++;
            while(l1 <= r1 && q1[r1] >= Min[i][k]) r1--;
            while(l2 <= r2 && q2[r2] <= Max[i][k]) r2--;
            id1[++r1] = id2[++r2] = i;
            q1[r1] = Min[i][k];
            q2[r2] = Max[i][k];
            if(i >= n) ans = min(q2[l2] - q1[l1], ans); 
        }
    }
    cout << ans << endl;
    return 0;
} 

初始化初始化初始化!!!

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容