HDU3308 LCIS(線段樹區間合併)
阿新 • • 發佈:2018-12-09
LCIS
傳送門1傳送門2 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 .
The next line has n integers.
The next m lines each has an operation:
OR
.
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
題意
找最長上升子串(區間).
分析
線段樹區間合併. 注意到在中的LCIS,可能在左兒子,可能在右兒子,還可能跨越左右. 跨越左右的即為左兒子最長上升字尾+右兒子最長上升字首.故線段樹需維護三個量:最長上升前後綴與子串(區間). 對於每個節點,
Tree[p].lmx>=Tree[p<<1 ].lmx,
Tree[p].rmx>=Tree[p<<1|1].rmx,
Tree[p].mx >=max(Tree[p<<1].mx,Tree[p<<1|1].mx
另外,若左兒子最右邊的數<右兒子左邊的數則左後綴與右字首之和為一個待選項.此時左後綴與右字首也有另外的待選項.
CODE
#include<iostream>
#include<cstdio>
#define FOR(i,a,b) for(int i=(a),i##_END_=(b);i<=i##_END_;i++)
#define Lson l,mid,p<<1
#define Rson mid+1,r,p<<1|1
#define N 100005
using namespace std;
void Rd(int &x) {
char c;x=0;
while((c=getchar())<48);
do x=(x<<1)+(x<<3)+(c^48);
while((c=getchar())>47);
}
int n,m;
int A[N];
struct SegT {int mx,lmx,rmx;} Tree[N<<2];
void Up(int l,int r,int p){
int len=r-l+1,mid=(l+r)>>1;
Tree[p].lmx=Tree[p<<1].lmx;
Tree[p].rmx=Tree[p<<1|1].rmx;
Tree[p].mx=max(Tree[p<<1].mx,Tree[p<<1|1].mx);
if(A[mid]<A[mid+1]){
if(Tree[p].rmx==(len>>1))Tree[p].rmx+=Tree[p<<1].rmx;
if(Tree[p].lmx==len-(len>>1))Tree[p].lmx+=Tree[p<<1|1].lmx;
Tree[p].mx=max(Tree[p].mx,Tree[p<<1].rmx+Tree[p<<1|1].lmx);
}
}
int Query(int l,int r,int nl,int nr,int p) {
if(l>=nl&&r<=nr)return Tree[p].mx;
int Mx=1,mid=(l+r)>>1;
if(nl<=mid) Mx=Query(l,mid,nl,nr,p<<1);
if(nr>=mid+1) Mx=max(Mx,Query(mid+1,r,nl,nr,p<<1|1));
if(A[mid]<A[mid+1])
Mx=max(Mx,min(mid-nl+1,Tree[p<<1].rmx)+min(nr-mid,Tree[p<<1|1].lmx));
return Mx;
}
void Build(int l,int r,int p){
if(l==r){
Tree[p].mx=Tree[p].lmx=Tree[p].rmx=1;
return;
}
int mid=(l+r)>>1;
Build(Lson),Build(Rson);
Up(l,r,p);
}
void Update(int l,int r,int x,int k,int p){
if(l==r){
A[l]=k;
return;
}
int mid=(l+r)>>1;
if(x<=mid)Update(l,mid,x,k,p<<1);
else Update(mid+1,r,x,k,p<<1|1);
Up(l,r,p);
}
int main() {
int T,a,b;
char chr[2];
scanf("%d",&T);
while(T--) {
scanf("%d %d",&n,&m);
FOR(i,1,n)Rd(A[i]);
Build(1,n,1);
while(m--) {
scanf("%s",chr);
Rd(a),Rd(b);
if(chr[0]=='Q') printf("%d\n",Query(1,n,a+1,b+1,1));
else Update(1,n,a+1,b,1);
}
}
return 0;
}