/*
题型:线段树;
解题思路:
在线段树的节点上保存lmax,rmax,max三个值,lmax表示从该节点左端点数递增的最长长度,rmax表示终点是该节点的右端点的最长长度,max表示该区间的最长长度
更新就是:如果左孩子的右端点小于右孩子的左端点,那么就合并左孩子rmax和右孩子的lmax;查询时和更新相似;
代码如下:
*/
#include<stdio.h> #include<string.h> struct node{ int l,r,x; node(){l=r=x=1;} node(int a,int b,int c):l(a),r(b),x(c){} void set(int a,int b,int c){ l=a; r=b; x=c;} }sum[400010]; int Max(int a,int b){ return a<b?b:a;} int S[100010]; void build(int i,int l,int r) { int mid,ans; if(l==r) { sum[i].set(1,1,1); return; } int a,b; mid=(l+r)/2; build(i<<1,l,mid); build(i<<1|1,mid+1,r); a=sum[i<<1].l;b=sum[i<<1|1].r; ans=Max(sum[i<<1].x,sum[i<<1|1].x); if(S[mid]<S[mid+1]){ ans=Max(ans,sum[i<<1].r+sum[i<<1|1].l); if(a==mid-l+1) a+=sum[i<<1|1].l; if(b==r-mid) b+=sum[i<<1].r; } sum[i].set(a,b,ans); } void update(int i,int l,int r,int p,int v) { if(l==r){ S[l]=v; return ; } int mid=(l+r)/2,ans,a,b; if(p<=mid)update(i<<1,l,mid,p,v); else update(i<<1|1,mid+1,r,p,v); a=sum[i<<1].l;b=sum[i<<1|1].r; ans=Max(sum[i<<1].x,sum[i<<1|1].x); if(S[mid]<S[mid+1]){ ans=Max(ans,sum[i<<1].r+sum[i<<1|1].l); if(a==mid-l+1) a+=sum[i<<1|1].l; if(b==r-mid) b+=sum[i<<1].r; } sum[i].set(a,b,ans); } int query(int i,int l,int r,int a,int b,int &ml,int &mr) { if(l==a&&r==b){ mr=sum[i].r;ml=sum[i].l; return sum[i].x; } int mid=(l+r)/2,ans,mml[2],mmr[2]; if(b<=mid)return query(i<<1,l,mid,a,b,ml,mr); if(a>mid) return query(i<<1|1,mid+1,r,a,b,ml,mr); ans=Max(query(i<<1,l,mid,a,mid,mml[0],mmr[0]),query(i<<1|1,mid+1,r,mid+1,b,mml[1],mmr[1])); ml=mml[0];mr=mmr[1]; if(S[mid]<S[mid+1]){ ans=Max(ans,mmr[0]+mml[1]); if(ml==mid-a+1) ml+=mml[1]; if(mr==b-mid) mr+=mmr[0]; } return ans; } int main() { char op[5]; int cas,n,m,i,a,b,x,y; scanf("%d",&cas); while(cas--) { scanf("%d%d",&n,&m); for(i=1;i<=n;i++)scanf("%d",&S[i]); build(1,1,n); while(m--) { scanf("%s%d%d",op,&a,&b);a++; if(op[0]=='U') update(1,1,n,a,b); else { b++; printf("%d\n",query(1,1,n,a,b,x,y)); } } } return 0; }