前言
大工程,用时1.5h
舒服~
题目
讲解
线段树板题,细节很多。
如果这道[USACO08FEB]Hotel G(洛谷)没有做过建议做了再来看。
这道题的思路就变得清晰易懂了。
为方便描述和理解,我们把先上升后下降的序列叫做山峰
。
对于一个区间,我们需要维护以下数据:
-
左端点开始的上升序列长度(ul)。
-
左端点开始的下降序列长度(dl)。
-
左端点开始的山峰长度(udl)。
-
右端点结束的上升序列长度(ur)。(从左往右是单增的)
-
右端点结束的下降序列长度(dr)。(从左往右是单减的)
-
右端点结束的山峰长度(udr)。(从左往右是先单增后单减的)
-
区间山峰最大值(ans)。
-
区间加的懒标记(lz)。
-
区间左端点值(l)。
-
区间右端点值(r)。
我们发现区间加对一个区间的答案并不影响,所以我们的重难点就在区间合并上。
区间加不多赘述。
(l,r)可以直接由子区间得到。
对于(ans),我们可以先取子区间(ans)的最大值,然后我们的(ans)更新就只可能是跨区间了,分类讨论即可。
(ul,ur,dl,dr,udl,udr)与(ans)类似,分类讨论即可。
其实合并区间总体上分为两部分:
一是子区间直接更新此区间。
二是跨区间更新。
对于这道题这个更新思路显得尤为重要,不然很容易混乱。
详见代码。
代码
#define lc (x<<1)
#define rc (x<<1|1)
struct SegmentTree
{
struct node
{
int ul,ur,dl,dr,udl,udr,ans;
LL lz,l,r;
}t[MAXN << 2];
void up(int x,int l,int mid,int r)
{
//子区间不跨区间,直接更新此区间
t[x].l = t[lc].l; t[x].r = t[rc].r;
t[x].ans = Max(t[lc].ans,t[rc].ans);
int llen = mid-l+1,rlen = r-mid;//左右区间长度
t[x].ul = t[lc].ul; t[x].dl = t[lc].dl;
t[x].ur = t[rc].ur; t[x].dr = t[rc].dr;
t[x].udl = t[lc].udl; t[x].udr = t[rc].udr;
//分类讨论跨区间更新
if(t[lc].r < t[rc].l)
{
if(t[lc].ul == llen) t[x].ul += t[rc].ul;
if(t[rc].ur == rlen) t[x].ur += t[lc].ur;
if(t[rc].udr == rlen) t[x].udr += t[lc].ur;
if(t[lc].ul == llen) t[x].udl = Max(t[x].udl,llen + t[rc].udl);
t[x].ans = Max(t[x].ans,t[rc].udl + t[lc].ur);
}
else if(t[lc].r > t[rc].l)
{
if(t[lc].dl == llen) t[x].dl += t[rc].dl;
if(t[rc].dr == rlen) t[x].dr += t[lc].dr;
if(t[lc].udl == llen) t[x].udl += t[rc].dl;
if(t[rc].dr == rlen) t[x].udr = Max(t[x].udr,rlen + t[lc].udr);
t[x].ans = Max(t[x].ans,t[lc].udr + t[rc].dl);
}
}
void down(int x)
{
if(!t[x].lz) return;
t[lc].l += t[x].lz; t[lc].r += t[x].lz; t[lc].lz += t[x].lz;
t[rc].l += t[x].lz; t[rc].r += t[x].lz; t[rc].lz += t[x].lz;
t[x].lz = 0;
}
void Build(int x,int l,int r)
{
if(l == r)
{
t[x].l = t[x].r = Read();
t[x].ul = t[x].ur = t[x].dl = t[x].dr = t[x].udl = t[x].udr = 1;
t[x].ans = 1;
t[x].lz = 0;
return;
}
int mid = (l+r) >> 1;
Build(lc,l,mid);
Build(rc,mid+1,r);
up(x,l,mid,r);
}
void Add(int x,int l,int r,int ql,int qr,int val)
{
if(ql <= l && r <= qr)
{
t[x].l += val; t[x].r += val; t[x].lz += val;
return;
}
int mid = (l+r) >> 1;
down(x);
if(ql <= mid) Add(lc,l,mid,ql,qr,val);
if(mid+1 <= qr) Add(rc,mid+1,r,ql,qr,val);
up(x,l,mid,r);
}
}st;
int main()
{
// freopen(".in","r",stdin);
// freopen(".out","w",stdout);
n = Read();
st.Build(1,1,n);
for(int T = Read(); T ;-- T)
{
int l = Read(),r = Read(),val = Read();
st.Add(1,1,n,l,r,val);
Put(st.t[1].ans,'
');
}
return 0;
}