题目: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
*/