Time Limit: 6000/2000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 7193 Accepted Submission(s): 3069
//最大递增子串sub可能是区间[l,r]中前缀部分,后缀部分或者中间部分(横跨两个子区间)。 //线段树维护信息:val(表节点的值),sub(最长上升子序列的长度),pre(最 //长上升前缀的长度),suf(最长上升后缀的长度).由于一个区间[L,R]内的LCIS, //可能在左半边,也可能跨越两边,也可能在右半边, #include<iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int maxn=100005; int val[maxn],suf[maxn*4],pre[maxn*4],sub[maxn*4]; void pushup(int id,int l,int r) { int m=(l+r)>>1; sub[id]=max(sub[id<<1],sub[id<<1|1]); if(val[m]<val[m+1]) sub[id]=max(sub[id],suf[id<<1]+pre[id<<1|1]); //如果两个子区间连续,左子区间后缀+右子区间前缀 pre[id]=pre[id<<1]; if((pre[id]==m-l+1)&&val[m]<val[m+1]) pre[id]+=pre[id<<1|1]; //如果前缀是左子区间的所有数并且左子区间右边界值小于右子区间左边界值 suf[id]=suf[id<<1|1]; if((suf[id]==r-m)&&val[m]<val[m+1]) suf[id]+=suf[id<<1]; //如果后缀是右子区间的所有数并且左子区间右边界值小于右子区间左边界值 } void build(int id,int l,int r) { if(l==r){ sub[id]=suf[id]=pre[id]=1; return; } int m=(l+r)>>1; build(id<<1,l,m); build(id<<1|1,m+1,r); pushup(id,l,r); } void update(int a,int b,int id,int l,int r) { if(l==r){ val[l]=b; sub[id]=suf[id]=pre[id]=1; return; } int m=(l+r)>>1; if(a<=m) update(a,b,id<<1,l,m); else update(a,b,id<<1|1,m+1,r); pushup(id,l,r); } int query(int ql,int qr,int id,int l,int r) { if(ql<=l&&qr>=r) return sub[id]; int m=(l+r)>>1; if(qr<=m) return query(ql,qr,id<<1,l,m); else if(ql>m) return query(ql,qr,id<<1|1,m+1,r); int subx=max(query(ql,qr,id<<1,l,m),query(ql,qr,id<<1|1,m+1,r)); int prex=min(qr-m,pre[id<<1|1]);//右子区间中在查询范围中的前缀 int sufx=min(m-ql+1,suf[id<<1]);//左子区间中在查询范围中的后缀 if(val[m]<val[m+1]) subx=max(subx,prex+sufx); return subx; } int main() { int t,n,m; scanf("%d",&t); while(t--){ scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) scanf("%d",&val[i]); build(1,1,n); char ch[3];int a,b; while(m--){ scanf("%s%d%d",ch,&a,&b); if(ch[0]==‘U‘) update(a+1,b,1,1,n); else if(ch[0]==‘Q‘) printf("%d\n",query(a+1,b+1,1,1,n)); } } return 0; }
原文:http://www.cnblogs.com/--ZHIYUAN/p/6517145.html