题目
n(n<=1e5)个数,m(m<=1e5)种操作,操作分两种,
U A B (0<=A<n,0<=B<=1e5)把A位置的数改成B
Q A B (0<=A<=B<n)询问[A,B]最长连续严格上升子段的长度
思路来源
https://blog.csdn.net/GodJing007/article/details/91556056?utm_source=app
题解
区间合并经典题目,每个点维护三个值,从左最长,从右最长和整段最长
注意合并的时候,要判断a[mid+1]>a[mid]时,才能从中间拼接,否则不能拼接
其余部分,和区间合并没区别,注意询问别越界
代码
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+10;
int t,n,m,a[N];
char s[5];
int x,y;
struct node
{
int l0,r0,s0;
}e[5*N];
void pushup(int p,int l,int r)
{
int mid=(l+r)/2;
bool ok=a[mid+1]>a[mid];
e[p].l0=e[p<<1].l0;
if(e[p<<1].l0==mid-l+1&&ok)e[p].l0+=e[p<<1|1].l0;
e[p].r0=e[p<<1|1].r0;
if(e[p<<1|1].r0==r-mid&&ok)e[p].r0+=e[p<<1].r0;
e[p].s0=max(e[p<<1].s0,e[p<<1|1].s0);
if(ok)e[p].s0=max(e[p].s0,e[p<<1].r0+e[p<<1|1].l0);
}
void build(int p,int l,int r)
{
e[p].l0=e[p].r0=e[p].s0=0;
if(l==r)
{
e[p].l0=e[p].r0=e[p].s0=1;
return;
}
int mid=(l+r)/2;
build(p<<1,l,mid);
build(p<<1|1,mid+1,r);
pushup(p,l,r);
}
void upd(int p,int l,int r,int x,int v)
{
if(l==r)
{
a[x]=v;
e[p].l0=e[p].r0=e[p].s0=1;
return;
}
int mid=(l+r)/2;
if(x<=mid)upd(p<<1,l,mid,x,v);
else upd(p<<1|1,mid+1,r,x,v);
pushup(p,l,r);
}
int ask(int p,int l,int r,int ql,int qr)
{
if(ql<=l&&r<=qr)return e[p].s0;
int ans=0,mid=(l+r)/2;
bool ok=a[mid+1]>a[mid];
if(ql<=mid)ans=max(ans,ask(p<<1,l,mid,ql,qr));
if(qr>mid)ans=max(ans,ask(p<<1|1,mid+1,r,ql,qr));
if(ql<=mid&&qr>mid&&ok)ans=max(ans,min(mid-ql+1,e[p<<1].r0)+min(qr-mid,e[p<<1|1].l0));
return ans;
}
int main()
{
scanf("%d",&t);
while(t--)
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;++i)
scanf("%d",&a[i]);
build(1,1,n);
while(m--)
{
scanf("%s%d%d",s,&x,&y);
if(s[0]=='U')
{
x++;
upd(1,1,n,x,y);
}
else if(s[0]=='Q')
{
x++;y++;
printf("%d\n",ask(1,1,n,x,y));
}
}
}
return 0;
}