LCIS
Time Limit: 6000/2000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 6069 Accepted Submission(s): 2635
Problem Description
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].
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).
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.
Sample Input
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 Q 4 7 Q 3 5 Q 0 2 Q 4 6 U 6 10 Q 0 9
Sample Output
1 1 4 2 3 1 2 5
题意:n个数从0到n-1,两种操作,第一种操作是U,A,B,把B位置的值用A来代替,第二种操作是查询区间【A,B】的最长连续严格上升序列。
思路:线段树区间合并题,维护3个变量,单点更新不需要pushdown,区间查询,查询和pushup的时候需要区间合并。
#include<stdio.h>
#include<algorithm>
using namespace std;
const int MAXN = 100005;
struct NODE{
int l,r;
int ls,rs,maxs;
//ls为从区间左边界开始的最长连续上升序列
//rs为从区间右边界开始的最长连续上升序列
//maxs为该区间的最长连续上升序列
}segTree[MAXN << 2];
int a[MAXN];
void pushup(int num)
{
segTree[num].ls = segTree[num << 1].ls;//父节点的ls与左儿子的ls相同
segTree[num].rs = segTree[num << 1 | 1].rs;//父节点的rs与右儿子的rs相同
//不考虑左区间与右区间最长连续上升序列可以合并的话,父节点的maxs
//为左右儿子大的那个maxs
segTree[num].maxs = max(segTree[num << 1].maxs,segTree[num << 1 | 1].maxs);
int mid = (segTree[num].l + segTree[num].r) >> 1;
//如果左区间与右区间最长连续上升序列可以合并的话
if(a[mid] < a[mid + 1]){
//如果可以合并,还需更新左边区间的ls和右边区间的rs
if(segTree[num << 1].ls == segTree[num << 1].r - segTree[num << 1].l + 1){
segTree[num].ls += segTree[num << 1 | 1].ls;
}
if(segTree[num << 1 | 1].rs == segTree[num << 1 | 1].r - segTree[num << 1 | 1].l + 1){
segTree[num].rs += segTree[num << 1].rs;
}
//更新maxs,左区间的rs+右区间的ls
segTree[num].maxs = max(segTree[num].maxs,segTree[num << 1].rs + segTree[num << 1 | 1].ls);
}
}
void build(int num,int l,int r)
{
segTree[num].l = l;
segTree[num].r = r;
if(l == r){
segTree[num].ls = segTree[num].rs = segTree[num].maxs = 1;
return;
}
int mid = (l + r) >> 1;
build(num << 1,l,mid);
build(num << 1 | 1,mid + 1,r);
pushup(num);
}
//单点更新,不需要pushdown
void update(int num,int pos)
{
if(segTree[num].l == segTree[num].r)
return;
int mid = (segTree[num].l + segTree[num].r) >> 1;
if(pos <= mid) update(num << 1,pos);
else update(num << 1 | 1,pos);
pushup(num);
}
//区间查询
int query(int num,int l,int r)
{
if(segTree[num].l == l && segTree[num].r == r)
return segTree[num].maxs;
int mid = (segTree[num].l + segTree[num].r) >> 1;
int ans = 0;
if(r <= mid){
ans = max(ans,query(num << 1,l,r));
}
else if(l > mid){
ans = max(ans,query(num << 1 | 1,l,r));
}
else{
ans = max(ans,query(num << 1,l,mid));
ans = max(ans,query(num << 1 | 1,mid + 1,r));
//可以合并,注意要小于区间长度
if(a[mid] < a[mid + 1]){
ans = max(ans,min(mid - l + 1,segTree[num << 1].rs) + min(r - mid,segTree[num << 1 | 1].ls));
}
}
return ans;
}
int main(void)
{
int T;
scanf("%d",&T);
while(T--){
int n,m;
scanf("%d%d",&n,&m);
for(int i = 1; i <= n; i++){
scanf("%d",&a[i]);
}
build(1,1,n);
while(m--){
int l,r;
char op[3];
int pos,v;
scanf("%s",op);
if(op[0] == 'Q'){
scanf("%d%d",&l,&r);
l++,r++;
printf("%d\n",query(1,l,r));
}
else{
scanf("%d%d",&pos,&v);
a[++pos] = v;
update(1,pos);
}
}
}
return 0;
}