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 ; }