[CF739C] Alyona and towers

前言

大工程,用时1.5h

舒服~

题目

洛谷

CF

讲解

线段树板题,细节很多。

如果这道[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,'\n');
	}
	return 0;
}
posted @ 2020-12-23 17:35  皮皮刘  阅读(153)  评论(0编辑  收藏  举报