$P1440\ 求m区间内的最小值$

$P1440\ 求m区间内的最小值$

\(problem\)

线段树 求 \(RMQ\)问题 \(orz\) 原因是因为我的\(ST\)表炸了
(我太弱了)
\(RMQ\)问题通常是求区间最值。 比如说 :\(X - Y\)的最大值?
这样的问题往往无从下手 我们需要一个解决\(RMQ\)问题的算法。
比如说是:\(ST\)表 , 线段树。
其实还有单调队列的方法。 其他题解也说到了。(代码简短)
可我还是不知道为什么我选了 \(ST\)表 && 线段树。
可能是因为我比较笨吧(大雾
先讲讲\(ST\)表吧 虽然说不能\(AC\) 但是我看见有人 用这个方法\(AC\)
\(ST\)表的思路主要是 预处理 然后 \(O(1)\)复杂度的查询 适合这种问题
用一个\(f[i][j]\) 来 表示 \(i\) ~ $ i + 2^j\(的最大值 从而到这样 这样子时间是完全\)ojbk$的 但是反观 内存 \(n\ log \ n\)的一个内存 \(N<=200w\) 所以显然不行
(如果有哪位神仙用\(ST\)表AC了麻烦点评测记录告诉我如何不\(MLE\))
评测记录:\(Here\)
所以去想线段树 线段树的查询大概是\(log\ n\)
\(n \ log \ n\) 也勉强过得去吧。
但是貌似没有单调队列快(还不是我弱)
回归正题 线段树 (分治的方法
首先我们需要定义数组 以及 建树

const int N = 2e6 + 10 ;
struct node {
    int l , r , w ;
#define lt k << 1
#define rt k << 1 | 1
}tree[N << 2] ;

不要问我为啥\(<<2\) 因为我也不知道 线段树的数组大小通常是\(N\)\(4\)

inline void build(int k,int l,int r) {
    if(l > r) return ;
    if(l == r) {
        tree[k].l = l , tree[k].r = r , tree[k].w = a[l] ;
        return ;
    }
    int mid = (l + r) >> 1 ;//分治Here
    build(lt , l , mid) ;
    build(rt , mid + 1 , r) ;
    tree[k].l = l , tree[k].r = r ;
    tree[k].w = min(tree[lt].w , tree[rt].w) ;
}

建完树之后我们需要做一个操作 : \(query\)(当然只是函数名我个人喜欢这种函数名)

inline int query(int k,int l,int r,int x,int y) {
    if(l > r) return 0 ;
    if(l >= x and r <= y) return tree[k].w ;
    int mid = (l + r) >> 1 ;
    int sum = inf ;
    if(x <= mid) sum = min(sum , query(lt , l , mid , x , y)) ;//分治
    if(y > mid) sum = min(sum , query(rt , mid + 1 , r , x , y)) ;
    return sum ;
}

所以易证时间复杂度 $O(n\log n) $

空间复杂度 \(O(N*4)\)

#include <bits/stdc++.h>
using namespace std ;

inline int rd() { int x = 0 ; int f = 1 ; register char c ;
#define gc c = getchar()
    while(isspace(gc)) ;
    if(c == '-') f = -1 , gc ;
    while(x = (x<<1) + (x<<3) + (c&15) , isdigit(gc)) ;
    return x * f ;
#undef gc
}

const int inf = INT_MAX >> 1 ;
const int N = 2e6 + 10 ;

struct node {
    int l , r , w ;
#define lt k << 1
#define rt k << 1 | 1
}tree[N << 2] ;

int n , m ;
int a[N] ;

inline void build(int k,int l,int r) {
    if(l > r) return ;
    if(l == r) {
        tree[k].l = l , tree[k].r = r , tree[k].w = a[l] ;
        return ;
    }
    int mid = (l + r) >> 1 ;
    build(lt , l , mid) ;
    build(rt , mid + 1 , r) ;
    tree[k].l = l , tree[k].r = r ;
    tree[k].w = min(tree[lt].w , tree[rt].w) ;
}

inline int query(int k,int l,int r,int x,int y) {
    if(l > r) return 0 ;
    if(l >= x and r <= y) return tree[k].w ;
    int mid = (l + r) >> 1 ;
    int sum = inf ;
    if(x <= mid) sum = min(sum , query(lt , l , mid , x , y)) ;
    if(y > mid) sum = min(sum , query(rt , mid + 1 , r , x , y)) ;
    return sum ;
}

signed main() {
    n = rd() , m = rd() ;
    for(register int i=1;i<=n;i++) a[i] = rd() ;
    build(1 , 1 , n) ;
    for(register int i=1;i<=n;i++) {
        int x = i - m , y = i - 1 ;
        if(x <= 0) x = 1 ;
        if(x > y) {
            puts("0") ;
            continue ;
        }
        printf("%d\n" , query(1 , 1 , n , x , y)) ;
    }
    return 0 ;
}
posted @ 2019-04-19 20:39 breezeღ 阅读( ...) 评论( ...) 编辑 收藏

猜你喜欢

转载自blog.csdn.net/qq_42628055/article/details/89410743
今日推荐