题目:http://acm.uestc.edu.cn/problem.php?pid=1425
题意:给你一个数列,每次回选择一个区间的数,或者把这些数都加上一个值,或者问你这些数的最长递增序列。。。
分析:这题对区间进行操作,很容易使我们想到线段树,但是,线段树要保存那些信息才能求得答案呢,成段的累加这个不是问题,只要加个延迟标记就行,最主要的是询问最长递增序列。。。
1.当然,我们肯定要保存区间的最大值,每次向上更新时,理首当然的取左右子树的最大值。。。但是如果两个区间合并出更长的序列呢?
2.保存每个区间左右边界的值,这个方便我们判断两个区间是否能合并,这样向上更新时就能知道是否会出现更优值了。。。
3.知道可能合并,那我们怎么求出现的更优值呢,当然,它会出现在中间,我们需要知道从左线段的右端可以到达的最左端 lmost,和右线段左端能到达的最右端rmost ,新的值就是 rmost-lmost+1,所以我们要保存所有线段左端点能到达的最右端,右端点能到达的最左端。。。。也就是lmost ,rmost
///毫无疑问:经典的LICS 线段树区间更新 /// 我们用lmax[rt] 表示 以左开端LIS,rmax[rt] 表示以右结尾的LIS,mmax[rt]表示全局的LIS #include<iostream> #include<algorithm> #include<cstdio> #include<cstring> using namespace std; const int maxn=100002; #define lson rt<<1,l,mid #define rson rt<<1|1,mid+1,r int lmax[maxn<<2],rmax[maxn<<2],mmax[maxn<<2],vall[maxn<<2],valr[maxn<<2],col[maxn<<2],sum[maxn<<2],flag[maxn<<2],n,m,t; char s[2]; void pushup(int rt,int l,int r) { int mid=(l+r)>>1; lmax[rt]=lmax[rt<<1];///左孩子的以左开端的LIS rmax[rt]=rmax[rt<<1|1];///右孩子的以右结尾的LIS mmax[rt]=max(mmax[rt<<1],mmax[rt<<1|1]); vall[rt]=vall[rt<<1],valr[rt]=valr[rt<<1|1]; if(valr[rt<<1]<vall[rt<<1|1]) { if(flag[rt<<1]) lmax[rt]+=lmax[rt<<1|1];///左孩子满,可以合并 if(flag[rt<<1|1])rmax[rt]+=rmax[rt<<1];///右孩子满,可以合并 mmax[rt]=max(mmax[rt],rmax[rt<<1]+lmax[rt<<1|1]);///右孩子左开端+左孩子右结尾 } if(mmax[rt]==r-l+1) flag[rt]=1; else flag[rt]=0; } void pushdown(int rt,int l,int r) { if(col[rt]) { col[rt<<1]+=col[rt]; col[rt<<1|1]+=col[rt]; vall[rt<<1]+=col[rt]; valr[rt<<1]+=col[rt]; vall[rt<<1|1]+=col[rt]; valr[rt<<1|1]+=col[rt]; col[rt]=0; } } void build(int rt,int l,int r) { lmax[rt]=rmax[rt]=mmax[rt]=flag[rt]=1; col[rt]=0; if(l==r) { scanf("%d",&vall[rt]); valr[rt]=vall[rt]; return; } int mid=(l+r)>>1; build(lson); build(rson); pushup(rt,l,r); } void updata(int rt,int l,int r,int L,int R,int num) { if(L<=l&&r<=R) { col[rt]+=num; vall[rt]+=num; valr[rt]+=num; return; } pushdown(rt,l,r); int mid=(l+r)>>1; if(mid>=L) updata(lson,L,R,num); if(mid<R) updata(rson,L,R,num); pushup(rt,l,r); } int query(int rt,int l,int r,int L,int R) { if(L <= l && r <= R) { return mmax[rt]; } int mid = (l+r)>>1; int ans = 0,ans1=0,ans2=0; if(mid >= L) ans1=query(lson,L,R); if(mid < R) ans2=query(rson,L,R); ans=max(ans1,ans2); if(valr[rt<<1]< vall[rt<<1|1]) { ans = max(ans,min(mid-L+1,rmax[rt<<1])+min(R-mid,lmax[rt<<1|1])); } return ans; } int main() { int cas=1; cin>>t; while(t--) { scanf("%d%d",&n,&m); int i,j,a,b,c; build(1,1,n); printf("Case #%d:\n",cas++); for(i=1; i<=m; i++) { scanf("%s",&s); scanf("%d %d",&a,&b); if(s[0]=='q') { printf("%d\n",query(1,1,n,a,b)); } else { scanf("%d",&c); updata(1,1,n,a,b,c); } } } return 0; } /* 1 5 6 0 1 2 3 3 q 1 4 a 1 5 1 q 1 5 a 5 5 1 a 5 5 -4 q 2 3 q 4 4 2 10 10 7 7 3 3 5 9 9 8 1 8 Q 6 6 U 3 4 Q 0 1 Q 0 5 Q 4 7 Q 3 5 Q 0 2 Q 4 6 U 6 10 Q 0 9 */