HDU 3308 LCIS (线段树区间合并)

时间:2022-01-15 16:47:58

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3308

题目很好懂,就是单点更新,然后求区间的最长上升子序列。

线段树区间合并问题,注意合并的条件是a[mid + 1] > a[mid],写的细心点就好了。

 #include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;
const int MAXN = 1e5 + ;
struct SegTree {
int l , r , lsum , sum , rsum;
}T[MAXN << ];
int a[MAXN]; void pushup(int p) {
int ls = p << , rs = (p << )| , mid = (T[p].r + T[p].l) >> ;
T[p].lsum = T[ls].lsum , T[p].rsum = T[rs].rsum;
if(T[p].lsum == T[ls].r - T[ls].l + ) {
T[p].lsum += (a[mid + ] > a[mid] ? T[rs].lsum : );
}
if(T[p].rsum == T[rs].r - T[rs].l + ) {
T[p].rsum += (a[mid + ] > a[mid] ? T[ls].rsum : );
}
T[p].sum = max(T[ls].sum , T[rs].sum);
int temp = (a[mid + ] > a[mid] ? T[ls].rsum + T[rs].lsum : );
T[p].sum = max(temp , T[p].sum);
} void build(int p , int l , int r) {
int mid = (l + r) >> ;
T[p].l = l , T[p].r = r;
if(l == r) {
T[p].lsum = T[p].rsum = T[p].sum = ;
return ;
}
build(p << , l , mid);
build((p << )| , mid + , r);
pushup(p);
} void updata(int p , int pos , int num) {
int mid = (T[p].l + T[p].r) >> ;
if(T[p].l == T[p].r && T[p].l == pos) {
a[pos] = num;
return ;
}
if(pos <= mid) {
updata(p << , pos , num);
}
else {
updata((p << )| , pos , num);
}
pushup(p);
} int query(int p , int l , int r) {
int mid = (T[p].l + T[p].r) >> ;
if(l == T[p].l && T[p].r == r) {
return T[p].sum;
}
if(r <= mid) {
return query(p << , l , r);
}
else if(l > mid) {
return query((p << )| , l , r);
}
else {
return max((a[mid + ] > a[mid] ? min(mid - l + , T[p << ].rsum) + min(T[(p << )|].lsum , r - mid) : ) ,
max(query(p << , l , mid) , query((p << )| , mid + , r) ) );
}
} int main()
{
int t , n , m;
scanf("%d" , &t);
while(t--) {
scanf("%d %d" , &n , &m);
for(int i = ; i <= n ; ++i) {
scanf("%d" , a + i);
}
build( , , n);
char q[];
int l , r;
while(m--) {
scanf("%s %d %d" , q , &l , &r);
if(q[] == 'Q') {
printf("%d\n" , query( , l + , r + ));
}
else {
updata( , l + , r);
}
}
}
return ;
}