移动窗口

http://poj.org/problem?id=2823

题意:给出n个数,窗口大小为k,窗口从1滑到n-k,问所以窗口内的最大最小值;

解法:单调队列存两个数据一个是值,一个是值的的下标。两个指针(首尾指针),单调增队列求最小值,每次询问队首元素下标是否超出

窗口范围,超出则队首指针向后移(剔除队首),然后队首值就是该窗口的最小值。

最大值同理。

//#include<bits/stdc++.h>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <iostream>
#include <string>
#include <stdio.h>
#include <queue>
#include <stack>
#include <map>
#include <set>
#include <string.h>
#include <vector>
#define ME(x , y) memset(x , y , sizeof(x))
#define SC scanf
#define rep(i , j , n) for(int i = j ; i <= n ; i++)
#define red(i , n , j)  for(int i = n ; i >= j ; i--)
#define INF  0x3f3f3f3f
#define mod 1000000007
#define PI acos(-1)
#define pii pair<int,int>
#define fi first
#define se second
using namespace std;
typedef long long ll ;
const int maxn = 1e6+10;
int a[maxn] ;
int val[maxn] ;
pair<int , int>que[maxn];

int main()
{
    int n , k ; cin >> n >> k;
    rep(i , 1 , n){
        scanf("%d" , &a[i]);
    }
    int front = 1 , rear = 0 , len = 0  ;
    rep(i , 1 , n){
        while(rear >= front && que[rear].fi >= a[i]){
            rear--;
        }
        if(rear >= front && i - que[front].se + 1 > k){
            front++;
        }
        que[++rear].fi = a[i];
        que[rear].se = i ;
        if(i >= k){
            val[++len] = que[front].fi ;
        }
    }
    rep(i , 1 , len){
        cout << val[i] << " " ;
    }
    cout << endl;
    front =  1 , rear = 0 , len = 0 ;
    rep(i , 1 , n){
        while(rear >= front && que[rear].fi <= a[i])
            rear--;
        if(rear >= front && i - que[front].se + 1 > k){
            front++;
        }
        que[++rear].fi = a[i] ;
        que[rear].se = i ;
        if(i >= k){
            val[++len] = que[front].fi;
        }
    }
    rep(i , 1 , len){
        cout << val[i] << " " ;
    }
    cout << endl;
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/nonames/p/12322025.html