题目大意:有一个长度为n(n≤10^6)的数列,依次查询区间[1,k],[2,k+1],[3,k+2]……[n-k+1,n]的最值。
显然,每次直接求k个数的最值,
时间复杂度达到O(n*k),
会TLE。
所以,我们要换位思考。
其实我们可以很容易地发现:第一次查询时,建立一棵范围为[1,k]的胜者树即可。
而第二次我们要做的就是:把第1个元素从这棵
树中删去,把第k+1个元素插入这棵树中。
这一过程可以简化为:把第1个元素所在的结点的值更换为第k+1个元素的值。之后,重复这个操作即可。
至此,问题迎刃而解。
注意一个细节:本题要查询的最值包括最大值和最小值。需要建立两棵树吗?不用。只需让每个结点储存两个最值即可。
代码:
# include <cstdio>
# define min(x,y) x<y?x:y
# define max(x,y) x>y?x:y
const int SIZE = 1000000+5 ;
struct Tnode {
int _min , _max ;
} tree[SIZE<<1];
int n , k , a[SIZE] , ans[2][SIZE] ;
//ans[0][i]表示区间[i,i+k]的最小值 //ans[1][i]表示区间[i,i+k]的最大值
void build_tree ( int , int , int ) ; //建树
void _insert ( int , int , int , int , int ) ; //修改+维护
int main () {
scanf ( "%d%d" , &n , &k ) ;
for ( int i=1 ; i!=n+1 ; ++i )
scanf ( "%d" , &a[i] ) ;
build_tree ( 1 , k , 1 ) ;
ans[0][0] = tree[1]._min ;
ans[1][0] = tree[1]._max ;
for ( int i=1 ; i!=n-k+1 ; ++i ) {
//第i次要把第i个元素所在的结点的值替换为第i+k个元素
//第1个元素在1号结点,第2个元素在2号结点……第k个元素在k号结点
//第(k+1)个元素在1号结点,第(k+2)个元素在2号结点……
//第i个元素在((i-1)%k)+1号结点。
_insert ( 1 , k , ((i-1)%k)+1 , a[i+k] , 1 ) ;
ans[0][i] = tree[1]._min ;
ans[1][i] = tree[1]._max ;
}
for ( int i=0 ; i!=2 ; ++i ) {
for ( int j=0 ; j!=n-k+1 ; ++j )
printf ( "%d " , ans[i][j] ) ;
printf ( "\n" ) ;
}
return 0 ;
}
void build_tree ( int _left , int _right , int _node ) {
if ( _left == _right )
tree[_node]._min = tree[_node]._max = a[_left] ;
else {
int _middle = (_left+_right) >> 1 ;
int l_child = _node<<1 ; //左子树根结点编号
int r_child = l_child+1 ; //右子树根结点编号
build_tree ( _left , _middle , l_child ) ;
build_tree ( _middle+1 , _right , r_child ) ;
tree[_node]._min = min ( tree[l_child]._min , tree[r_child]._min ) ;
tree[_node]._max = max ( tree[l_child]._max , tree[r_child]._max ) ;
}
return ;
}
void _insert ( int _left , int _right , int _k , int new_value , int _node ) {
if ( _left == _right ) //找到要被修改的结点
tree[_node]._min = tree[_node]._max = new_value ;
else {
int _middle = (_left+_right) >> 1 ;
int l_child = _node<<1 ;
int r_child = l_child+1 ;
if ( _k <= _middle ) //判断要修改的是在左子树还是右子树
_insert ( _left , _middle , _k , new_value , l_child ) ;
else
_insert ( _middle+1 , _right , _k , new_value , r_child ) ;
//维护
tree[_node]._min = min ( tree[l_child]._min , tree[r_child]._min ) ;
tree[_node]._max = max ( tree[l_child]._max , tree[r_child]._max ) ;
}
return ;
}