/*
题型:线段树;
解题思路:
在线段树的节点上保存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;
}