$P1440\ 求m区间内的最小值$
线段树 求 \(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 ;
}