zoukankan      html  css  js  c++  java
  • [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,'
    ');
    	}
    	return 0;
    }
    
  • 相关阅读:
    python 利用爬虫获取页面上下拉框里的所有国家
    python3 requests 进行接口测试、爬虫使用总结
    Tomcat设置最佳线程数总结
    Java中实现对象的比较:Comparable接口和Comparator接口
    堆排序算法
    快速排序算法2---以第一个元素作为主元
    字符串匹配---暴力匹配算法
    快速排序算法
    Spring中@Autowired注解与自动装配
    Spring的注解
  • 原文地址:https://www.cnblogs.com/PPLPPL/p/14179882.html
Copyright © 2011-2022 走看看