hdu 3308 LCIS
给n个数,有两个操作,第一个操作单点更新,第二个操作询问区间的最长严格连续递增子序列
因为是连续,所以线段树区间合并的时候答案只可能是两个子区间的答案或者合并后的中间拼接的最大值。
维护五个量,lnum区间左端点的值,rnum区间右端点的值,llen区间从左端点起的最长LCIS,rlen区间从右端点向后的最长LCIS。len区间最长LCIS。
Pushup的时候注意llen可能占据整个左区间且左区间右端点小于右区间左端点就更新llen,rlen同理。
len可能是两个子区间的答案,合并后的llen或者rlen或者如果左区间的rlen与右区间的llen可以合并的和。
查询的时候需要注意如果查询的区间在线段树的两个区间里,那么合并rlen与llen时注意把查询的区间长度与rlen+llen取min。
#include <bits/stdc++.h> #define Lson l,mid,rt<<1 #define Rson mid+1,r,rt<<1|1 using namespace std; const int M = 1e5+7; int _,n,q,a[M],pos; struct Tree { int l,r; int lnum,rnum;//区间最左边的数字以及区间最右边的数字 int llen,rlen,len;//左边的连续递增长度,右边的连续递增长度,区间最长递增长度 }tree[M<<2]; void Pushup(int rt){ tree[rt].lnum=tree[rt<<1].lnum;//区间左端点为左区间左端点 tree[rt].rnum=tree[rt<<1|1].rnum;//区间右端点为右区间右端点 tree[rt].llen=tree[rt<<1].llen; tree[rt].rlen=tree[rt<<1|1].rlen; tree[rt].len=max(tree[rt<<1].len,tree[rt<<1|1].len);//取两个子区间连续递增较大的 if(tree[rt<<1].llen==tree[rt<<1].r-tree[rt<<1].l+1&&tree[rt<<1].rnum<tree[rt<<1|1].lnum){ tree[rt].llen+=tree[rt<<1|1].llen; } tree[rt].len=max(tree[rt].len,tree[rt].llen);//如果左区间连续递增为整个区间且右端点小于右区间左端点则更新递增左区间与递增长度 if(tree[rt<<1|1].rlen==tree[rt<<1|1].r-tree[rt<<1|1].l+1&&tree[rt<<1].rnum<tree[rt<<1|1].lnum){ tree[rt].rlen+=tree[rt<<1].rlen; } tree[rt].len=max(tree[rt].len,tree[rt].rlen); if(tree[rt<<1].rnum<tree[rt<<1|1].lnum) tree[rt].len=max(tree[rt].len,tree[rt<<1].rlen+tree[rt<<1|1].llen);//左右区间的右递增区间与左递增区间如果可以合并就更新答案 } void build(int l,int r,int rt){ tree[rt].l=l;tree[rt].r=r; if(l==r){ tree[rt].lnum=tree[rt].rnum=a[l]; tree[rt].len=tree[rt].llen=tree[rt].rlen=1; return ; } int mid=(l+r)>>1; build(Lson); build(Rson); Pushup(rt); } void update(int l,int r,int rt,int v){ if(l==r){ tree[rt].lnum=tree[rt].rnum=v; return ; } int mid=(l+r)>>1; if(pos<=mid) update(Lson,v); else update(Rson,v); Pushup(rt); } int query(int L,int R,int l,int r,int rt){ if(L<=l&&r<=R){ return tree[rt].len; } int mid=(l+r)>>1; if(L>mid) return query(L,R,Rson); else if(R<=mid) return query(L,R,Lson); else{//当查询区间贯穿两个区间 int k1,k2,k3=0,k4=0; k1=query(L,R,Lson);k2=query(L,R,Rson);//可能在两个区间中 if(tree[rt<<1].rnum<tree[rt<<1|1].lnum){//如果可以将两个区间的右左区间合并则合并 k3=min(mid-L+1,tree[rt<<1].rlen);//mid-L+1 k4=min(R-mid,tree[rt<<1|1].llen);//R-mid } return max(k4+k3,max(k1,k2));//可能无法合并所以初始k3=k4=0 } } int main(){ scanf("%d",&_); while(_--){ scanf("%d%d",&n,&q); for(int i=1;i<=n;i++) scanf("%d",&a[i]); build(1,n,1); while(q--){ char op[3]; scanf("%s",op); if(op[0]=='U'){ int v; scanf("%d%d",&pos,&v);pos++; update(1,n,1,v); } else{ int l,r; scanf("%d%d",&l,&r); printf("%d\n",query(l+1,r+1,1,n,1)); } } } return 0; }

浙公网安备 33010602011771号