LCIS
题目大意:
编号为0~n-1的n个数组,
两种操作:
Q l r:查询区间[l,r]中最长连续递增子串的长度
U p x:将下标为p的点更新为x
输入描述
T(表示样例数量)
n m
n个数
m行操作
输出描述
每个查询操作输出查询结果
解题思路
线段树的单点修改,区间查询;由于是单点修改,则修改时只会将值向上传递,即只涉及pushup。 pushup操作如何合并两个子区间,可以记录下区间的左右边缘的最长增长子串(lmx,rmx)。合并时考虑边界合并即可。
区间的vmx 就是 max(左区间的vmx,右区间的vmx),如果左区间的右端和右区间的左端是连续递增的,就还要把他们两端的长度加起来,三者中最大的就是区间的vmx。
区间的lmx(rmx)就是左区间的lmx(右区间的rmx),如果整个左区间(右区间)都是递增的,那么还要加上右区间的lmx(左区间的rmx)。
runtime err或wa的debug经验:本题交了快10次了才ac,一直RE/WA。基本上写线段树没有一次是直接ac的。一般遇到过这几个原因:1.int溢出 2.忘记初始化 3.思路正确,但是某段代码出现手误(最主要) 4.思路错误,对线段树的掌握不够熟练。
代码
#include<bits/stdc++.h>
using namespace std;
int n,m;
struct node
{
int l,r;
int vmx;
int lmx,rmx;
}tr[400005];
int a[100005];
void pushup(node &x,node &y,node &z)
{
if(y.lmx==y.r-y.l+1&&a[y.r]<a[z.l])
{
x.lmx=y.lmx+z.lmx;
}
else x.lmx=y.lmx;
if(z.rmx==z.r-z.l+1&&a[y.r]<a[z.l])
{
x.rmx=y.rmx+z.rmx;
}
else x.rmx=z.rmx;
x.vmx=max(y.vmx,z.vmx);
if(a[y.r]<a[z.l])
{
x.vmx=max(x.vmx,y.rmx+z.lmx);
}
}
void pushup(int u)
{
pushup(tr[u],tr[u<<1],tr[u<<1|1]);
}
void build(int u,int l,int r)
{
tr[u].l=l;
tr[u].r=r;
if(l==r)
{
tr[u].vmx=tr[u].rmx=tr[u].lmx=1;
return ;
}
int mid=l+r>>1;
build(u<<1,l,mid);build(u<<1|1,mid+1,r);
pushup(u);
}
node query(int u,int l,int r)
{
if(tr[u].l>=l&&tr[u].r<=r)return tr[u];
int mid=tr[u].l+tr[u].r>>1;
node res;
if(mid>=r)res=query(u<<1,l,r),res.l=tr[u].l,res.r=tr[u].r;
else if(mid<l)res=query(u<<1|1,l,r),res.l=tr[u].l,res.r=tr[u].r;
else
{
res.l=tr[u].l;
res.r=tr[u].r;
auto left=query(u<<1,l,r);
auto right=query(u<<1|1,l,r);
pushup(res,left,right);
}
return res;
}
void modify(int u,int pos,int x)
{
if(tr[u].l==tr[u].r&&tr[u].l==pos)
{
a[pos]=x;
return ;
}
int mid=tr[u].l+tr[u].r>>1;
if(pos<=mid)modify(u<<1,pos,x);
else modify(u<<1|1,pos,x);
pushup(u);
}
void solve()
{
cin>>n>>m;
for(int i=0;i<n;i++)cin>>a[i];
build(1,0,n-1);
while(m--)
{
char op;cin>>op;
if(op=='Q')
{
int l,r;
cin>>l>>r;
cout<<query(1,l,r).vmx<<endl;
}
else
{
int pos,x;cin>>pos>>x;
modify(1,pos,x);
}
}
}
int main()
{
int T;
cin>>T;
while(T--)
solve();
}