链接:点击打开链接
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; }