题目大意:给定n(1 ≤ N ≤ 50,000)个数,每次求指定区间内的最大值减去最小值的差。
分析:这道题目实际上就是一道简单RMQ,可以用st算法解决,也可以用胜者树。
st算法代码如下:
# include <cstdio>
# define max(a,b) a>b?a:b
# define min(a,b) a<b?a:b
const int SIZE = 50000+5 ;
int N , Q , log2[SIZE] , f[2][30][SIZE];
//f[0][i][j]储存以j为起始点的2^i个数的最大值 //f[1][i][j]储存以j为起始点的2^i个数的最小值
void init () ; //初始化,建表
void work () ; //处理查询
int _query ( int , int ) ; //查询指定区间[a,b]的结果
int main () {
init () ;
work () ;
return 0 ;
}
void init () {
scanf ( "%d%d" , &N , &Q ) ;
for ( int i=1 ; i!=N+1 ; ++i ) {
scanf ( "%d" , &f[0][0][i] ) ;
f[1][0][i] = f[0][0][i] ;
//2^0=1,因此连续2^0个数的最值就是自己本身
}
for ( int i=2 ; i!=N+1 ; ++i ) //建立以2为底的对数表
log2[i] = log2[i>>1] + 1;
//建表
for ( int i=1 ; i!=log2[N]+1 ; ++i ) //i表示当前是连续2^i个数的最值
for( int j=1 ; j<=N-(1<<i)+1 ; ++j ) { //j表示当前起始点
f[0][i][j] = max ( f[0][i-1][j] , f[0][i-1][j+(1<<(i-1))] ) ;
f[1][i][j] = min ( f[1][i-1][j] , f[1][i-1][j+(1<<(i-1))] ) ;
}
return ;
}
int _query ( int _left , int _right ) {
int k = log2[_right-_left+1];
int _max = max(f[0][k][_left],f[0][k][_right-(1<<k)+1]) ;
int _min = min(f[1][k][_left],f[1][k][_right-(1<<k)+1]) ;
return _max - _min ;
}
void work () {
for ( int i=0; i!=Q ; ++i ) {
int _l , _r ;
scanf ( "%d%d" , &_l , &_r ) ;
printf ( "%d\n" , _query ( _l , _r ) ) ;
}
return ;
}
当然除了用st算法,也可以用胜者树实现此题,具体如下:
当我们查询区间[a,b]内的最值并定义m=(1+n)/2时,显然有三种情况:
- 区间[a,b]完全在[1,m]内。
- 区间[a,b]完全在[m+1,n]内。
- 区间[a,b]被分为[a,m]和[m+1,b]两个区间。
代码如下:
# include <cstdio>
#define min(x,y) x<y?x:y
#define max(x,y) x>y?x:y
const int SIZE = 500005 ;
struct Tnode {
int min_value , max_value ;
} tree[SIZE<<1];
int N , Q , h[SIZE] ;
int A[200005] , B[200005] ;
void init();
void buildtree ( int , int , int ) ;
Tnode query ( int , int , int , int , int ) ;
int main () {
init();
buildtree ( 1 , N , 1 ) ;
for ( int i=0 ; i!=Q ; ++i ) {
Tnode tmp=query(1,N,A[i],B[i],1);
printf ( "%d\n" , tmp.max_value-tmp.min_value ) ;
}
return 0 ;
}
void init () {
scanf ( "%d%d" , &N , &Q ) ;
for ( int i=1 ; i!=N+1 ; ++i )
scanf ( "%d" , &h[i] ) ;
for ( int i=0 ; i!=Q ; ++i )
scanf ( "%d%d" , &A[i] , &B[i] ) ;
return ;
}
void buildtree ( int left , int right , int node ) {
if ( left == right ) {
tree[node].min_value = tree[node].max_value = h[left] ;
} else {
int middle = ( left + right ) >> 1 ;
buildtree ( left , middle , node<<1 ) ;
buildtree ( middle+1 , right , (node<<1)+1 ) ;
tree[node].min_value = min ( tree[node<<1].min_value , tree[(node<<1)+1].min_value ) ;
tree[node].max_value = max ( tree[node<<1].max_value , tree[(node<<1)+1].max_value ) ;
}
return ;
}
Tnode query ( int left , int right , int low , int high , int node ) {
//查询区间[low,high]的最值 //保证left<=low且right>=high,即[low,high]一定在[left,right]内
if ( left==low&&right==high ) return tree[node]; //找到目标
int middle = ( left + right ) >> 1 ;
if ( high <= middle ) return query ( left , middle , low , high , node<<1 ) ; //情况1
else if ( low > middle ) return query ( middle+1 , right , low , high , (node<<1)+1 ) ;//情况2
Tnode res,le,ri;
le=query(left , middle , low , middle , node<<1); //求左区间
ri=query(middle+1 , right , middle+1 , high , (node<<1)+1); //求右区间
res.min_value=min(le.min_value,ri.min_value);
res.max_value=max(le.max_value,ri.max_value);
return res;
}