链接:点击打开链接
You have two operations:
U A B: replace the Ath number by B. (index counting from 0)
Q A B: output the length of the longest consecutive increasing subsequence (LCIS) in [a, b].
Each case starts with two integers n , m(0<n,m<=10 5).
The next line has n integers(0<=val<=10 5).
The next m lines each has an operation:
U A B(0<=A,n , 0<=B=10 5)
OR
Q A B(0<=A<=B< n).
单点修改,求区间最长连续上升序列。
这道题关键在于又两个子节点更新父节点以及区间查询的操作。
父节点的最长连续上升序列难道就是两个子节点的最大值吗? 肯定不是,中间那个点肯定会有影响的。
那么我们应该维护区间的三个信息。
区间的最长连续上升序列,tmp【】
区间头为起点的最长连续上升序列 le【】
以区间尾为终点的最长连续上升序列 ri【】
那么更新操作就变成这样的了:
void up(int root,int l,int r)
{
int mid=l+r>>1;
if(le[root<<1]==mid-l+1&&a[mid]<a[mid+1]) le[root]=le[root<<1]+le[root<<1|1];
else le[root]=le[root<<1];
if(ri[root<<1|1]==r-mid&&a[mid]<a[mid+1]) ri[root]=ri[root<<1]+ri[root<<1|1];
else ri[root]=ri[root<<1|1];
tmp[root]=max(tmp[root<<1],tmp[root<<1|1]);
if(a[mid]<a[mid+1]) tmp[root]=max(tmp[root],ri[root<<1]+le[root<<1|1]);
}
最后就是区间查询的操作了,
定义当前节点为root,区间最左端为nowa,最右端为nowb,需要查询的区间为 L--r。
当 nowa==L nowb==r时 ,直接return tmp【root】;
如果区间全在左儿子中,那么return root<<1 nowa (nowa+nowb)/2 L r
如果区间全在右儿子中,那么return root<<1|1 1+(nowa+nowb)/2 nowb L r
最后就是左右儿子都有。那么先取左右儿子的最大值,在考虑中间的情况。
对于坐儿子,min ( ri[root<<1], (nowa+nowb)/2-L+1 ),这里要说明一下为什么不是直接取ri【root<<1】,因为L不一定能达到nowa的位置,还有就是L是不可能超过nowa的。
同理右儿子也是一样。
AC代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=100010;
const ll inf=1e18;
int T,n,m,x,y;
char s[5];
int tmp[maxn<<2],le[maxn<<2],ri[maxn<<2];
int a[maxn];
void up(int root,int l,int r)
{
int mid=l+r>>1;
if(le[root<<1]==mid-l+1&&a[mid]<a[mid+1]) le[root]=le[root<<1]+le[root<<1|1];
else le[root]=le[root<<1];
if(ri[root<<1|1]==r-mid&&a[mid]<a[mid+1]) ri[root]=ri[root<<1]+ri[root<<1|1];
else ri[root]=ri[root<<1|1];
tmp[root]=max(tmp[root<<1],tmp[root<<1|1]);
if(a[mid]<a[mid+1]) tmp[root]=max(tmp[root],ri[root<<1]+le[root<<1|1]);
}
void build(int root,int l,int r)
{
if(l==r)
{
scanf("%d",&a[l]);
tmp[root]=le[root]=ri[root]=1;
return;
}
int mid=l+r>>1;
build(root<<1,l,mid);
build(root<<1|1,mid+1,r);
up(root,l,r);
}
void updata(int root,int l,int r,int pos)
{
int mid=l+r>>1;
if(l==r) return;
if(pos<=mid) updata(root<<1,l,mid,pos);
else updata(root<<1|1,mid+1,r,pos);
up(root,l,r);
}
int query(int root,int nowa,int nowb,int l,int r)
{
if(l==nowa&&nowb==r) return tmp[root];
int mid=nowa+nowb>>1;
if(r<=mid) return query(root<<1,nowa,mid,l,r);
if(l>mid) return query(root<<1|1,mid+1,nowb,l,r);
int t1=query(root<<1,nowa,mid,l,mid);
int t2=query(root<<1|1,mid+1,nowb,mid+1,r);
int ans=max(t1,t2);
if(a[mid]<a[mid+1])
ans= max(ans,min(ri[root<<1],mid-l+1)+min(le[root<<1|1],r-mid));
return ans;
}
int main()
{
scanf("%d",&T);
while(T--)
{
scanf("%d%d",&n,&m);
build(1,0,n-1);
while(m--)
{
scanf("%s%d%d",s,&x,&y);
if(s[0]=='Q') printf("%d\n",query(1,0,n-1,x,y));
else
{
a[x]=y;
updata(1,0,n-1,x);
}
}
}
return 0;
}