Given n integers.
You have two operations:
U A B: replace the Ath number by B. (index counting from 0)
Q A B: output the length of the longest consecutive increasing subsequence (LCIS) in [a, b].
Input
T in the first line, indicating the case number.
Each case starts with two integers n , m(0<n,m<=10 5).
The next line has n integers(0<=val<=10 5).
The next m lines each has an operation:
U A B(0<=A,n , 0<=B=10 5)
OR
Q A B(0<=A<=B< n).
Output
For each Q, output the answer.
就是求区间最长上升字串,因为会更改值,所以不能dp,要用线段树区间合并
直接上代码,有详细注释
#include<iostream>
#include <stdio.h>
#include <algorithm>
#include <stdlib.h>
#define LL long long
using namespace std;
const int MAX = 1e6 + 50;
struct date{
int len; // 记录区间长度
int ls, rs, ms; //记录左边开始的最长上升字串,右边开始的最长下降字串,以及该区间的最长上升字串的长度
int ln, rn; // 记录该区间左右端点的值
} tree[MAX << 2];
int a[MAX];
void PushUp(int rt){
int li = rt << 1;
int ri = rt << 1 | 1;
tree[rt].ls = tree[li].ls;
tree[rt].rs = tree[ri].rs;
tree[rt].ms = max(tree[li].ms, tree[ri].ms);
tree[rt].ln = tree[li].ln;
tree[rt].rn = tree[ri].rn;
tree[rt].len = tree[li].len + tree[ri].len;
if(tree[li].rn < tree[ri].ln){ //如果左区间的右端点的值小于右区间的左端点
if(tree[li].len == tree[li].ls){ //如果左区间的以左开始的最长上升字串长的长度等于区间长度,则可以和右区间从左开始的最长上升子串合并
tree[rt].ls += tree[ri].ls;
}
if(tree[ri].len == tree[ri].rs){
tree[rt].rs += tree[li].rs;
}
tree[rt].ms = max(tree[rt].ms, tree[li].rs + tree[ri].ls); //判断ms的最大值
}
}
void Build(int l, int r, int rt){
if(l == r){
tree[rt].ln = tree[rt].rn = a[l];
tree[rt].ls = tree[rt].rs = tree[rt].ms = 1;
tree[rt].len = 1;
return ;
}
int m = (l + r) >> 1;
Build(l, m, rt << 1);
Build(m + 1, r, rt << 1 | 1);
PushUp(rt);
}
int Le, Ri; //但点更新时Le为下标,Ri为值, 区间查询时Le, Ri分别为左右端点
void Update(int l, int r, int rt){
if(l == r){
tree[rt].ln = tree[rt].rn = Ri;
return ;
}
int m = (l + r) >> 1;
if(Le <= m){
Update(l, m, rt << 1);
}
if(Le > m){
Update(m + 1, r, rt << 1 | 1);
}
PushUp(rt);
}
int QueryRange(int l, int r, int rt){
if(Le <= l && r <= Ri){
return tree[rt].ms;
}
int m = (l + r) >> 1;
if(Ri <= m){
return QueryRange(l, m, rt << 1);
}
if(Le > m){
return QueryRange(m + 1, r, rt << 1 | 1);
}
int t1 = QueryRange(l, m, rt << 1);
int t2 = QueryRange(m + 1, r, rt << 1 | 1);
int t3 = 0;
int li = rt << 1;
int ri = rt << 1 | 1;
if(tree[li].rn < tree[ri].ln){ //如果左区间的右端点的值小于右区间的左端点的值
t3 = min(m - Le + 1, tree[li].rs) + min(Ri - m, tree[ri].ls);
}
return max(max(t1, t2), t3);
}
int main(){
int t;
scanf("%d", &t);
while(t--){
int n, p;
scanf("%d%d", &n, &p);
for(int i = 1; i <= n; i++){
scanf("%d", &a[i]);
}
Build(1, n, 1);
while(p--){
char c;
scanf(" %c%d%d", &c, &Le, &Ri);
Le++; //因为我们建树是从1开始的
if(c == 'Q'){
Ri++;
int ans = QueryRange(1, n, 1);
printf("%d\n", ans);
} else{
Update(1, n, 1);
}
}
}
return 0;
}