http://acm.hdu.edu.cn/showproblem.php?pid=3308
题意:
给你一串数字,并给你一些操作,操作分为两种,一种是将数字中的某一个该成另外
一个值,还有一种是询问给定区间中的最长上升序列长度。
思路:
线段树。单点更新。 区间需要记录的内容为:
max[idx] , 区间idx内的最大上升连续序列的长度。
val[idx] : 区间的值(其实可以省略)。
lval[idx]: 区间idx的左端点的值
rval[idx] : idx区间内的右端点的值
llen[idx] : idx区间内的左端点的连续上升序列的长度
rlen[idx] : idx区间内右端点的连续上升序列的长度。
代码:
#include<stdio.h>
#include<string.h>
#define LL(a) ( (a)<<1 )
#define RR(a) ( (a)<<1|1 )
#define MIN(a,b) ( (a)>(b)?(b):(a) )
int T ,N ,Q;
const int MAXN = 100010 ;
int val[MAXN*6] ; //区间的值
int max[MAXN*6] ; //区间的最大长度
int lval[MAXN*6] ; //区间左值
int rval[MAXN*6] ; //区间右值
int llen[MAXN*6] ;
int rlen[MAXN*6] ;
void PUSH_UP(int l ,int r, int idx){
int mid = (l + r) >> 1;
max[idx] = 0 ;
if( max[idx] < max[ LL(idx) ] )
max[idx] = max[ LL(idx) ] ;
if( max[idx] < max[ RR(idx) ])
max[idx] = max[ RR(idx) ] ;
if( rval[ LL(idx) ] < lval[ RR(idx) ] ){
int a = rlen[ LL(idx) ] + llen[ RR(idx) ] ;
if( max[idx] < a )
max[idx] = a ;
}
lval[idx] = lval[ LL(idx) ] ;
rval[idx] = rval[ RR(idx) ] ;
if(llen[ LL(idx) ] < mid-l+1 ){
llen[idx] = llen[ LL(idx) ] ;
}
else{
if( rval[ LL(idx) ] < lval[ RR(idx) ]){
llen[idx] = llen[ LL(idx) ] + llen[ RR(idx) ] ;
}
else{
llen[idx] = llen[ LL(idx) ] ;
}
}
if( rlen[ RR(idx) ] < r-mid ){
rlen[idx] = rlen[ RR(idx) ] ;
}
else{
if( rval[ LL(idx) ] < lval[ RR(idx) ]){
rlen[idx] = rlen[ RR(idx) ] + rlen[ LL(idx) ] ;
}
else{
rlen[idx] = rlen[ RR(idx) ];
}
}
}
void build(int l ,int r, int idx){
if(l == r){
scanf("%d",&val[idx]);
max[idx] = 1 ;
lval[idx] = val[idx] ;
rval[idx] = val[idx] ;
rlen[idx] = llen[idx] = 1 ;
return ;
}
int mid = (l + r) >> 1 ;
build( l , mid , LL(idx) );
build( mid+1 , r , RR(idx) );
PUSH_UP(l ,r , idx) ;
}
void update(int l ,int r, int idx, int pos , int v ){
if( l == r ){
val[idx] = v ;
max[idx] = 1 ;
rval[idx] = lval[idx] = val[idx] ;
rlen[idx] = llen[idx] = 1 ;
return ;
}
int mid = (l + r) >> 1 ;
if( pos <= mid ) update(l , mid , LL(idx) , pos ,v );
else update(mid+1, r, RR(idx) , pos ,v );
PUSH_UP(l ,r , idx) ;
}
int query(int l ,int r, int idx , int a , int b){
if(l==a && r==b){
return max[idx] ;
}
int mid = (l + r) >> 1;
if( b<=mid ) return query(l , mid, LL(idx) ,a , b);
else if(mid < a) return query(mid+1,r, RR(idx) , a, b);
else{
int l1 = query(l,mid,LL(idx),a , mid );
int l2 = query(mid+1, r , RR(idx) , mid+1, b );
int max_len = l1 > l2 ? l1 : l2 ;
if( rval[ LL(idx) ] < lval[ RR(idx) ] ){
int aa = mid - a + 1 ;
int bb = b - mid ;
aa = MIN( aa , rlen[ LL(idx) ] ); //这里需要求一个MIN
bb = MIN( bb , llen[ RR(idx) ] );
if( max_len < aa + bb )
max_len = aa + bb ;
}
return max_len ;
}
}
int main(){
char op[5] ;
int a, b ;
scanf("%d",&T);
for(int cas=1;cas<=T;cas++){
scanf("%d %d",&N,&Q);
build(1,N , 1 );
for(int i=1;i<=Q;i++){
scanf("%s %d %d",op,&a,&b);
if( op[0] == 'Q' ) {
a++ ; b++ ;
printf("%d\n", query(1, N ,1 , a, b ));
}
else{
a++ ;
update(1, N ,1 , a ,b );
}
}
}
return 0 ;
}