题目:
给一个长度为 NN 的数组,一个长为 KK 的滑动窗体从最左端移至最右端,你只能看到窗口中的 KK 个数,每次窗体向右移动一位。找出窗体在各个位置时的最大值和最小值。
思路:
网上好多人都是用的单调队列,这里给出一个用线段树的方法(如果没用O2优化甚至不一定能过,不好用hhh)。
可以将每一段的最大最小值记下来作为线段树的节点。
代码:
#include <bits/stdc++.h>
#define Pa pair< int, int >
#define MaxN 1000001
using namespace std;
typedef struct {
int max, min;
int left, right;
} node;
queue< Pa > que;
node tree[ MaxN << 2 ];
int line[ MaxN ];
void pushup( int po ) {
tree[ po ].max = max( tree[ po << 1 ].max, tree[ po << 1 | 1 ].max );
tree[ po ].min = min( tree[ po << 1 ].min, tree[ po << 1 | 1 ].min );
return;
}
void bulitree( int po, int left, int right ) {
if ( left == right ) {
tree[ po ].left = left;
tree[ po ].right = right;
tree[ po ].min = line[ left ];
tree[ po ].max = tree[ po ].min;
} else {
int mid = ( left + right ) >> 1;
tree[ po ].left = left, tree[ po ].right = right;
bulitree( po << 1, left, mid );
bulitree( po << 1 | 1, mid + 1, right );
pushup( po );
}
}
Pa query( int po, int left, int right ) {
if ( tree[ po ].left >= left && tree[ po ].right <= right ) {
Pa p;
p.first = tree[ po ].max, p.second = tree[ po ].min;
return p;
} else {
Pa p, q;
p.first = 0, p.second = 1000000001 ;
int mid = ( tree[ po ].left + tree[ po ].right ) >> 1;
if ( left <= mid ) {
p = query( po << 1, left, right );
}
if ( right > mid ) {
q = query( po << 1 | 1, left, right );
p.first = max( p.first, q.first );
p.second = min( p.second, q.second );
}
return p;
}
}
int main( ) {
int i, j, k;
int N, K;
scanf("%d %d", &N, &K );
for ( i = 1; i <= N; i ++ ) {
scanf("%d", &line[ i ] );
}
bulitree( 1, 1, N );
for ( i = 1; i <= N - K + 1; i++ ) {
que.push( query( 1, i, i + K - 1 ) );
printf("%d ", que.back( ).second );
}
cout << endl;
while ( !que.empty( ) ) {
printf("%d ", que.front( ).first );
que.pop( );
}
return 0;
}