题意:有T(t<10)组数据,给你N个数,M个操作(N和M都小于100000)。操作有两种类型,(1)“q a b”,查询区间[a,b]里的最长连续上升序列的长度。(2)“a l r v”,将区间[l,r]里的数全部增加v。
要记录区间里的最长的序列长度是多少,用mx来记录。由于最长的连续上升序列可以在区间的左端点,右端点,所以在线段树里增加两个域lmx和rmx,分别表示,在区间的端点处,分别向右向左的最长的满足条件的序列长度。但是还有可能出现在中间,所以又增加两个域lval和rval,分别表示区间端点的值是多少。合并的时候,判断左儿子的rval是否小于右儿子lval,如果满足,这个区间的mx可能为左儿子的rmx加上右儿子的lmx。另外,这个区间的mx可能是左儿子的mx或者右儿子的mx。
在更新当前区间的lmx时,如果左子区间的lmx等于左子区间的长度,那么当前区间的lmx就要加上右儿子的lmx。更新当前区间的rmx时同理。
另外在查询的时候,要注意,有可能当前区间的lmx大于mid-st+1,所以要在其中取一个较小值,同理rmx有可能大于ed-mid。
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
#define LL(x) (x<<1)
#define RR(x) (x<<1|1)
#define MID(a,b) (a+((b-a)>>1))
const int N=100005;
struct node
{
int lft,rht;
int lmx,rmx,mx;
int lval,rval,add;
void fun(int tmp)
{ add+=tmp; lval+=tmp; rval+=tmp; }
int len(){return rht-lft+1;}
int mid(){return MID(lft,rht);}
void init(){ lmx=rmx=mx=add=0; }
};
int y[N],n,m;
struct Segtree
{
node tree[N*4];
void down(int ind)
{
if(tree[ind].add)
{
tree[LL(ind)].fun(tree[ind].add);
tree[RR(ind)].fun(tree[ind].add);
tree[ind].add=0;
}
}
void up(int ind)
{
tree[ind].lmx=tree[LL(ind)].lmx;
tree[ind].rmx=tree[RR(ind)].rmx;
tree[ind].lval=tree[LL(ind)].lval;
tree[ind].rval=tree[RR(ind)].rval;
tree[ind].mx=max(tree[LL(ind)].mx,tree[RR(ind)].mx);
if(tree[LL(ind)].rval<tree[RR(ind)].lval)
{
if(tree[LL(ind)].lmx==tree[LL(ind)].len())
tree[ind].lmx+=tree[RR(ind)].lmx;
if(tree[RR(ind)].rmx==tree[RR(ind)].len())
tree[ind].rmx+=tree[LL(ind)].rmx;
tree[ind].mx=max(tree[ind].mx,tree[LL(ind)].rmx+tree[RR(ind)].lmx);
}
tree[ind].mx=max(tree[ind].mx,max(tree[ind].lmx,tree[ind].rmx));
}
void build(int lft,int rht,int ind)
{
tree[ind].lft=lft; tree[ind].rht=rht;
tree[ind].init();
if(lft==rht)
{
tree[ind].lval=tree[ind].rval=y[lft];
tree[ind].lmx=tree[ind].rmx=tree[ind].mx=1;
}
else
{
int mid=tree[ind].mid();
build(lft,mid,LL(ind));
build(mid+1,rht,RR(ind));
up(ind);
}
}
void updata(int st,int ed,int ind,int valu)
{
int lft=tree[ind].lft,rht=tree[ind].rht;
if(st<=lft&&rht<=ed) tree[ind].fun(valu);
else
{
down(ind);
int mid=tree[ind].mid();
if(st<=mid) updata(st,ed,LL(ind),valu);
if(ed> mid) updata(st,ed,RR(ind),valu);
up(ind);
}
}
int query(int st,int ed,int ind)
{
int lft=tree[ind].lft,rht=tree[ind].rht;
if(st<=lft&&rht<=ed) return tree[ind].mx;
else
{
down(ind);
int mid=tree[ind].mid();
if(ed<=mid) return query(st,ed,LL(ind));
else if(st>mid) return query(st,ed,RR(ind));
else
{
int mid=tree[ind].mid();
int mx1=query(st,ed,LL(ind));
int mx2=query(st,ed,RR(ind));
int tmp1=0,tmp2=0;
if(tree[LL(ind)].rval<tree[RR(ind)].lval)
{
tmp1=min(mid-st+1,tree[LL(ind)].rmx);
tmp2=min(ed-mid,tree[RR(ind)].lmx);
}
return max(max(mx1,mx2),tmp1+tmp2);
}
}
}
}seg;
int main()
{
int t,t_cnt=0;
scanf("%d",&t);
while(t--)
{
char str[10];
int a,b,c;
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++) scanf("%d",&y[i]);
seg.build(1,n,1);
printf("Case #%d:\n",++t_cnt);
while(m--)
{
scanf("%s",str);
if(str[0]=='q')
{
scanf("%d%d",&a,&b);
printf("%d\n",seg.query(a,b,1));
}
else
{
scanf("%d%d%d",&a,&b,&c);
seg.updata(a,b,1,c);
}
}
}
return 0;
}