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; }