线段树处理区间合并的问题。主要是记录一个区间包括左端点的最长的长度,包括右端点的最长的长度,整个区间的最长的长度,这三个信息。这样在合并两个区间时有足够的信息支持求出合并后区间最大的连续递增序列的长度。
查询时注意细节,特别是(a,b)分两段查询时,具体见代码。
#include<stdio.h> #include<string.h> #include<algorithm> #define MAX 100010 using namespace std; int A[MAX],L[4*MAX+1],R[4*MAX+1],len[4*MAX+1]; void build(int l,int r,int rt) { if( l==r ) { len[rt]=L[rt]=R[rt]=1; return ; } int m=(l+r)/2; build(l,m,rt<<1); build(m+1,r,rt<<1|1); if( A[m]<A[m+1]) { if( L[rt<<1] == m-l+1 ) L[rt]=L[rt<<1]+L[rt<<1|1]; else L[rt]=L[rt<<1]; if( R[rt<<1|1] == r-m ) R[rt]=R[rt<<1]+R[rt<<1|1]; else R[rt]=R[rt<<1|1]; int LEN=R[rt<<1]+L[rt<<1|1]; len[rt]=max( max(len[rt<<1],len[rt<<1|1]),LEN ); } else { L[rt]=L[rt<<1]; R[rt]=R[rt<<1|1]; len[rt]=max( len[rt<<1],len[rt<<1|1] ); } } void update(int pos,int l,int r,int rt) { if( l==r && l==pos ) { len[rt]=L[rt]=R[rt]=1; return ; } int m=(l+r)/2; if( pos<=m ) update(pos,l,m,rt<<1); else update(pos,m+1,r,rt<<1|1); if( A[m]<A[m+1]) { if( L[rt<<1] == m-l+1 ) L[rt]=L[rt<<1]+L[rt<<1|1]; else L[rt]=L[rt<<1]; if( R[rt<<1|1] == r-m ) R[rt]=R[rt<<1]+R[rt<<1|1]; else R[rt]=R[rt<<1|1]; int LEN=R[rt<<1]+L[rt<<1|1]; len[rt]=max( max(len[rt<<1],len[rt<<1|1]),LEN ); } else { L[rt]=L[rt<<1]; R[rt]=R[rt<<1|1]; len[rt]=max( len[rt<<1],len[rt<<1|1] ); } } int query(int a,int b,int l,int r,int rt) { if(l==a && r==b) { return len[rt]; } int m=(l+r)/2; if( b<=m ) return query(a,b,l,m,rt<<1); else if( a>m ) return query(a,b,m+1,r,rt<<1|1); else { int ans1=query(a,m,l,m,rt<<1); int ans2=query(m+1,b,m+1,r,rt<<1|1); if( A[m]<A[m+1] ) { return max( max( min(R[rt<<1],m-a+1)+min(L[rt<<1|1],b-m),ans1),ans2 ); } else return max(ans1,ans2); } } int main() { int n,m,i,j,t; char ch[10]; int a,b; scanf("%d",&t); while(t--) { scanf("%d%d",&n,&m); for(i=1;i<=n;i++) scanf("%d",A+i); build(1,n,1); for(i=1;i<=m;i++) { scanf("%s",ch); if( ch[0]=='Q') { scanf("%d%d",&a,&b); printf("%d\n",query(a+1,b+1,1,n,1)); }else { scanf("%d%d",&a,&b); A[a+1]=b; update(a+1,1,n,1); } } } return 0; }