题目大意
给出n个数:
你可以对其进行以下两种操作:
U A B: 把第A个数的值替换为B
Q A B: 查询在区间[a, b]内的最长连续上升子序列的长度
题解
单点更新和区间合并
需要维护三个域:区间LCIS长度的最值maxl,包含左端点LCIS的长度最大值lmaxl,包含右端点的LCI长度S的最大值rmaxl,合并的时候和hotel差不多,在查询区间的时候要注意,如果最长的长度是跨越了两个自区间的话,长度不能简单的认为就是rmaxl[s<<1]+lmaxl[s<<1|1],而是min(qr,m+lmaxl[s<<1|1])-max(ql,m-rmaxl[s<<1]+1)+1(ql和qr分别为当前节点的左右端点,m为中点)。
代码:
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; #define MAXN 100005 #define lson l,m,s<<1 #define rson m+1,r,s<<1|1 int maxl[MAXN<<2],lmaxl[MAXN<<2],rmaxl[MAXN<<2],val[MAXN<<2]; void PushUp(int s,int m,int p) { lmaxl[s]=lmaxl[s<<1]; rmaxl[s]=rmaxl[s<<1|1]; maxl[s]=max(maxl[s<<1],maxl[s<<1|1]); if(val[p]<val[p+1]) { if(lmaxl[s<<1]==(m-(m>>1))) lmaxl[s]+=lmaxl[s<<1|1]; if(rmaxl[s<<1|1]==(m>>1)) rmaxl[s]+=rmaxl[s<<1]; maxl[s]= max(maxl[s],rmaxl[s<<1]+lmaxl[s<<1|1]); } } void build(int l,int r,int s) { if(l==r) { scanf("%d",&val[r]); maxl[s]=lmaxl[s]=rmaxl[s]=1; return; } int m=(l+r)>>1; build(lson); build(rson); PushUp(s,r-l+1,m); } void update(int p,int d,int l,int r,int s) { if(l==r) { val[p]=d; return; } int m=(l+r)>>1; if(p<=m) update(p,d,lson); else update(p,d,rson); PushUp(s,r-l+1,m); } int query(int ql,int qr,int l,int r,int s) { if(ql<=l&&r<=qr) return maxl[s]; int m=(l+r)>>1,ans=0; if(ql<=m) ans=max(ans,query(ql, qr,lson)); if(qr>m) ans=max(ans,query(ql,qr,rson)); if(val[m]<val[m+1]) ans=max(ans,min(qr,m+lmaxl[s<<1|1])-max(ql,m-rmaxl[s<<1]+1)+1); return ans; } int main(void) { char op[5]; int n,m,T; scanf("%d",&T); while(T--) { int a,b; scanf("%d%d",&n,&m); build(0,n-1,1); while(m--) { scanf("%s",op); if(op[0]=='Q') { scanf("%d%d",&a,&b); printf("%d\n",query(a,b,0,n-1,1)); } else { scanf("%d%d",&a,&b); update(a,b,0,n-1,1); } } } return 0; }