HDU - 3308 LCIS
题目
给你长度为 n 的序列,两种操作,1、更新某个点的值,2、查询某个区间里最长连续上升子序列长度。操作一共 m 次。( n , m < 1 e 5 n, m < 1e5 n,m<1e5)
分析
经典的线段树区间合并题目
首先要维护区间的三个值
- 区间最长连续上升子序列长度
- 区间以左端点开始的最长连续上升子序列的长度
- 区间以右端点结束的最长连续上升子序列的长度
最麻烦的就是pushup 函数的编写,一定要搞清楚合并之间的逻辑关系
查询的时候要注意边界(L, R)
我用的线段树数组写法,感觉比较简洁。剩下的代码注释有详解。
#include <cstdio>
#include <iostream>
#include <cstring>
#include <cmath>
#include <algorithm>
#define INF 0x3f3f3f3f
#define d(x) cout << (x) << endl
#define lson l, m, rt<<1
#define rson m+1, r, rt<<1|1
// #include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll mod = 9999991;
const int N = 1e5 + 10;
int t, n, m, x, y;
int tr[N << 2], a[N], lx[N << 2], rx[N << 2];
//tr区间最长 lx左端点为起点最长 rx右端点为终点最长
void pushup(int rt, int l_len, int r_len, int m){ //参数: 根, 左区间长度, 右区间长度, 区间中点
int L = rt << 1, R = rt << 1 | 1; //左右儿子
bool tag = (a[m + 1] > a[m]); //判断区间中间的连续性, 下面区间合并的依据
lx[rt] = lx[L] + ((lx[L] == l_len && tag) ? lx[R] : 0); //更新 lx,当左儿子的 lx 等于左区间长度 && 区间中间连续,加上右儿子的lx
rx[rt] = rx[R] + ((rx[R] == r_len && tag) ? rx[L] : 0); //更新 rx,同上
tr[rt] = max(max(tr[L], tr[R]), (tag) ? (rx[L] + lx[R]) : 0);
}
void build(int l, int r, int rt){
if(l == r){
tr[rt] = lx[rt] = rx[rt] = 1;
return;
}
int m = l + r >> 1;
build(lson);
build(rson);
pushup(rt, m - l + 1, r - m, m);
}
void update(int l, int r, int rt, int pos, int v){
if(l == r){ //找到 pos位置
tr[rt] = lx[rt] = rx[rt] = 1; //更改值,重新跟新此点性质
return;
}
int m = l + r >> 1;
if(pos <= m)
update(lson, pos, v);
else
update(rson, pos, v);
pushup(rt, m - l + 1, r - m, m); //注意左右区间长度计算
}
int query(int l, int r, int rt, int L, int R){
if(l == L && r == R){
return tr[rt];
}
int m = l + r >> 1;
if(R <= m){ //查询区间全在左边
query(lson, L, R);
}else if(L > m){ //查询区间全在右边
query(rson, L, R);
}else{ //查询区间左右都有
int left = query(lson, L, m);
int right = query(rson, m+1, R);
int ans = 0;
if(a[m + 1] > a[m]){ //区间边界要好好看清楚,不能超过(L,R)的限制
ans = min(m - L + 1, rx[rt << 1]) + min(R - m, lx[rt << 1 | 1]);
}
return max(max(left, right), ans);
}
}
int main()
{
scanf("%d", &t);
while(t--){
scanf("%d%d", &n, &m);
for(int i = 0; i < n; i++){
scanf("%d", &a[i]);
}
build(0, n-1, 1);
char str[10];
string ss;
while(m--){
scanf("%s%d%d", &str, &x, &y);
if(str[0] == 'U'){
a[x] = y;
update(0, n - 1, 1, x, y);
}else{
printf("%d\n", query(0, n - 1, 1, x, y));
}
}
}
return 0;
}
/*
1
10 10
7 7 3 3 5 9 9 8 1 8
Q 6 6
U 3 4
Q 0 1
Q 0 5
*/