感觉线段树的递归还好hhh
但被这个连续递增子序列折腾的够呛hhh
每个节点不仅仅要保存当前最长序列的大小,还要保存前缀和后缀最长序列的大小,以达到正确合并
(自己完全想不出来hhhh)
开始看了代码也是一阵懵逼,把树画出来之后好看很多
#include <algorithm>
#include <cmath>
#include <cstring>
#include <iostream>
#define lson rt << 1
#define rson rt << 1 | 1
using namespace std;
const int e = 1000000;
int num[ e ];
int pre[ e << 2 ]; //保存当前区间从最左开始,连续增长序列的大小(前缀)
int suf[ e << 2 ]; //保存当前区间从最右开始,连续增长序列的大小(后缀)
int mid[ e << 2 ]; //保存当前区间整个,连续增长序列的大小
// 修改pre,mid,suf保证区间内的序列长度
void pushup ( int rt, int l, int r ) {
mid[ rt ] = max ( mid[ lson ], mid[ rson ] ); //默认的序列大小为左右两个孩子的序列大小中较大的数
pre[ rt ] = pre[ lson ]; //根的前缀由左孩子的前缀决定
suf[ rt ] = suf[ rson ]; //根的后缀由右孩子的后缀决定
int m = ( l + r ) >> 1;
int len = r - l + 1;
if ( num[ m ] < num[ m + 1 ] ) { //当前根的左右孩子可以连成一条新的连续序列
mid[ rt ] = max ( mid[ rt ], suf[ lson ] + pre[ rson ] ); //左孩子后缀 + 右孩子前缀
if ( pre[ lson ] == len - len / 2 ) //如果左孩子前缀的大小等于左孩子这段区间的大小
pre[ rt ] += pre[ rson ]; //则根节点的前缀就可以再连上右孩子的前缀
if ( suf[ rson ] == len / 2 ) //右孩子同理
suf[ rt ] += suf[ lson ];
}
}
void build ( int rt, int l, int r ) {
if ( l == r ) {
mid[ rt ] = pre[ rt ] = suf[ rt ] = 1;
return;
}
int m = ( l + r ) >> 1;
build ( lson, l, m );
build ( rson, m + 1, r );
pushup ( rt, l, r );
}
//单节点更新
void update ( int rt, int l, int r, int idx, int val ) {
if ( l == r )
if ( l == idx ) {
num[ idx ] = val;
pre[ rt ] = mid[ rt ] = suf[ rt ] = 1;
return;
}
int m = ( l + r ) >> 1;
if ( idx <= m )
update ( lson, l, m, idx, val );
if ( idx > m )
update ( rson, m + 1, r, idx, val );
pushup ( rt, l, r );
}
// l,r-->now
// L,R-->required
int query ( int rt, int l, int r, int L, int R ) {
//完全在区间里
if ( l >= L && r <= R )
return mid[ rt ];
int m = ( l + r ) >> 1;
//完全在左孩子的区间里
if ( R <= m )
return query ( lson, l, m, L, R );
//完全在右孩子的区间里
if ( L > m )
return query ( rson, m + 1, r, L, R );
//部分在左区间部分在右区间
int res = max ( query ( lson, l, m, L, R ), query ( rson, m + 1, r, L, R ) );
if ( num[ m ] < num[ m + 1 ] ) {
int prex = min ( suf[ lson ], m - L + 1 ); //取左孩子后缀 和 所求区间在左孩子区间里的大小 的 较小值
int suf = min ( pre[ rson ], R - m );
res = max ( res, prex + suf );
}
return res;
}
int main () {
int T;
scanf ( "%d", &T );
while ( T-- ) {
int n, m;
scanf ( "%d%d", &n, &m );
for ( int i = 1; i <= n; ++i )
scanf ( "%d", &num[ i ] );
build ( 1, 1, n );
while ( m-- ) {
char ins[ 5 ];
int a, b;
scanf ( "%s%d%d", ins, &a, &b );
if ( ins[ 0 ] == 'U' )
update ( 1, 1, n, ++a, b );
else if ( ins[ 0 ] == 'Q' ) {
int c = query ( 1, 1, n, ++a, ++b );
printf ( "%d\n", c );
}
}
}
return 0;
}