zoukankan      html  css  js  c++  java
  • 【CF1371F】Raging Thunder

    前言

    昨天晚上提交了 N 遍,甚至合并部分还改了一个写法,但是都在某个相同意义的一行显示 uninitialized value usage
    最后不知道改了什么,准备在洛谷提交一发然后走人,结果今天早上过来一看就 A 了???
    细思极恐 2333。

    \(\operatorname{Update:}\) 似乎有神仙还写动态 dp ?有空回来补一补。

    题目

    题目链接:https://codeforces.com/problemset/problem/1371/F
    \(n\) 个连续的传送带,第 \(i\) 个传送带左右分别有编号为 \(i-1\)\(i\) 的洞。每个传送带有一个传送方向。
    假设第 \(i\) 个传送带是向前传送且上面有一个球,那么

    • 如果第 \(i-1\) 个传送带是向后传送或者 \(i=1\),那么球会掉落至第 \(i-1\) 个洞里。
    • 如果第 \(i-1\) 个传送带是向前传送,那么球会到第 \(i-1\) 个传送带上。

    向后传送同理。现在有若干询问,每次询问给出 \(l,r\),意思是将 \([l,r]\) 的传送带反向。然后询问如果在 \([l,r]\) 的传送带内各放上一个球,那么最终球最多的洞中会有多少个球。

    思路

    首先可以把若干个 “>>><<” 看做一个块,也就是求会落到同一个洞里的区间看做一个块。
    这道题一眼看过去就很线段树。我们考虑将 \([l,mid]\)\((mid,r]\) 合并时,区间 \([l,r]\) 最多能放的球数 \(ans\) 就等于左右区间各自的 \(ans\) 以及 \([l,mid]\) 的最右一个块和 \((mid,r]\) 最左一个块产生的贡献的最大值。
    所以我们在线段树的每一个节点上维护 \(llen,lpos,rlen,rpos\) 分别表示最左/右的块的长度以及求会落到哪一个洞内。
    那么合并时,分别讨论四种情况,以合并最左的块为例:(| 表示 \(mid\) 的位置)

    • 如果 \([l,mid].llen\) 等于其区间长度,那么需要考虑以下三种情况:>>>|<<<>>>|><<><<|<<<
    • 否则 \([l,r]\) 最左的块就和 \([l,mid]\) 一样。

    合并最右区间同理。具体细节请自行思考。反正也不是很难233
    那么接下来就是区间修改操作了。我们发现直接修改不好在较优复杂度内重新维护那四个信息。但是在不修改其子区间的情况下,一个区间就只会有两种情况(正着和反着),所以我们可以在维护正着的四个信息时,同时维护如果把这个区间反过来的话的四个信息。维护其实是同理的,都是从子区间向上合并。
    那如果修改区间 \([l,r]\),那么就把该区间的正反的四个标记互换。然后给这个区间打上懒标记。下一次要其子区间信息时再向下维护。
    对于区间询问,其实和合并时一个道理的。我直接暴力维护一个八元组 \((l,r,llen,lpos,rlen,rpos,ans,len)\),然后将每一个子区间合并。
    时间复杂度 \(O(n\log n)\)

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    
    const int N=500010;
    int n,Q,ql,qr;
    char ch[N];
    
    struct Treenode
    {
    	int l,r,lpos,rpos,llen,rlen,ans,len;
    	
    	friend Treenode operator +(Treenode p,Treenode q)
    	{
    		Treenode x;
    		int mid=p.r;
    		x.l=p.l; x.r=q.r;
    		if (p.llen==p.len && p.lpos>=mid && q.lpos<=mid)
    			x.lpos=mid,x.llen=p.llen+q.llen;
    		else if (p.llen==p.len && p.lpos>=mid && q.lpos>mid)
    			x.lpos=q.lpos,x.llen=p.llen+q.llen; 
    		else if (p.llen==p.len && p.lpos<mid && q.lpos<=mid)
    			x.lpos=p.lpos,x.llen=p.llen+q.llen;
    		else 
    			x.lpos=p.lpos,x.llen=p.llen;
    			
    		if (q.rlen==q.len && p.rpos>=mid && q.rpos<=mid)
    			x.rpos=mid,x.rlen=p.rlen+q.rlen;
    		else if (q.rlen==q.len && p.rpos>=mid && q.rpos>mid)
    			x.rpos=q.rpos,x.rlen=p.rlen+q.rlen;
    		else if (q.rlen==q.len && p.rpos<mid && q.rpos<=mid)
    			x.rpos=p.rpos,x.rlen=p.rlen+q.rlen;
    		else
    			x.rpos=q.rpos,x.rlen=q.rlen;
    			
    		x.ans=max(p.ans,q.ans);
    		if (p.rpos>=mid || q.lpos<=mid) x.ans=max(x.ans,p.rlen+q.llen);
    		return x;
    	}
    };
    
    struct SegTree
    {
    	int l[N*4],r[N*4],lpos[2][N*4],rpos[2][N*4],llen[2][N*4],rlen[2][N*4],ans[2][N*4],len[N*4],lazy[N*4];
    	
    	void rev(int x)
    	{
    		lazy[x]^=1;
    		swap(llen[0][x],llen[1][x]); swap(lpos[0][x],lpos[1][x]);
    		swap(rlen[0][x],rlen[1][x]); swap(rpos[0][x],rpos[1][x]);
    		swap(ans[0][x],ans[1][x]);
    	}
    	
    	void pushup(int x)
    	{
    		int mid=(l[x]+r[x])>>1;
    		for (int id=0;id<=1;id++)
    		{
    			if (llen[id][x*2]==len[x*2] && lpos[id][x*2]>=mid && lpos[id][x*2+1]<=mid)
    				lpos[id][x]=mid,llen[id][x]=llen[id][x*2]+llen[id][x*2+1];
    			else if (llen[id][x*2]==len[x*2] && lpos[id][x*2]>=mid && lpos[id][x*2+1]>mid)
    				lpos[id][x]=lpos[id][x*2+1],llen[id][x]=llen[id][x*2]+llen[id][x*2+1]; 
    			else if (llen[id][x*2]==len[x*2] && lpos[id][x*2]<mid && lpos[id][x*2+1]<=mid)
    				lpos[id][x]=lpos[id][x*2],llen[id][x]=llen[id][x*2]+llen[id][x*2+1];
    			else
    				lpos[id][x]=lpos[id][x*2],llen[id][x]=llen[id][x*2];
    				
    			if (rlen[id][x*2+1]==len[x*2+1] && rpos[id][x*2]>=mid && rpos[id][x*2+1]<=mid)
    				rpos[id][x]=mid,rlen[id][x]=rlen[id][x*2]+rlen[id][x*2+1];
    			else if (rlen[id][x*2+1]==len[x*2+1] && rpos[id][x*2]>=mid && rpos[id][x*2+1]>mid)
    				rpos[id][x]=rpos[id][x*2+1],rlen[id][x]=rlen[id][x*2]+rlen[id][x*2+1];
    			else if (rlen[id][x*2+1]==len[x*2+1] && rpos[id][x*2]<mid && rpos[id][x*2+1]<=mid)
    				rpos[id][x]=rpos[id][x*2],rlen[id][x]=rlen[id][x*2]+rlen[id][x*2+1];
    			else
    				rpos[id][x]=rpos[id][x*2+1],rlen[id][x]=rlen[id][x*2+1];
    				
    			ans[id][x]=max(ans[id][x*2],ans[id][x*2+1]);
    			if (rpos[id][x*2]>=mid) ans[id][x]=max(ans[id][x],rlen[id][x*2]+llen[id][x*2+1]);
    			if (lpos[id][x*2+1]<=mid) ans[id][x]=max(ans[id][x],rlen[id][x*2]+llen[id][x*2+1]);
    		}
    	}
    	
    	void pushdown(int x)
    	{
    		if (lazy[x])
    		{
    			lazy[x]=0;
    			rev(x*2); rev(x*2+1);
    		}
    	}
    	
    	void build(int x,int ql,int qr)
    	{
    		l[x]=ql; r[x]=qr; len[x]=qr-ql+1;
    		if (ql==qr)
    		{
    			ans[0][x]=llen[0][x]=rlen[0][x]=ans[1][x]=llen[1][x]=rlen[1][x]=1;
    			if (ch[ql]=='<') lpos[0][x]=rpos[0][x]=ql-1,lpos[1][x]=rpos[1][x]=qr;
    			if (ch[ql]=='>') lpos[0][x]=rpos[0][x]=qr,lpos[1][x]=rpos[1][x]=ql-1;
    			return;
    		}
    		int mid=(ql+qr)>>1;
    		build(x*2,ql,mid); build(x*2+1,mid+1,qr);
    		pushup(x);
    	}
    		
    	void update(int x,int ql,int qr)
    	{
    		if (l[x]==ql && r[x]==qr)
    		{
    			rev(x);
    			return;
    		}
    		pushdown(x);
    		int mid=(l[x]+r[x])>>1;
    		if (qr<=mid) update(x*2,ql,qr);
    		else if (ql>mid) update(x*2+1,ql,qr);
    		else update(x*2,ql,mid),update(x*2+1,mid+1,qr);
    		pushup(x);
    	}
    	
    	Treenode query(int x,int ql,int qr)
    	{
    		if (l[x]==ql && r[x]==qr)
    			return (Treenode){l[x],r[x],lpos[0][x],rpos[0][x],llen[0][x],rlen[0][x],ans[0][x],len[x]};
    		pushdown(x);
    		int mid=(l[x]+r[x])>>1;
    		if (qr<=mid) return query(x*2,ql,qr);
    		if (ql>mid) return query(x*2+1,ql,qr);
    		return query(x*2,ql,mid)+query(x*2+1,mid+1,qr);
    	}
    }seg;
    
    int main()
    {
    	scanf("%d%d",&n,&Q);
    	scanf("%s",ch+1);
    	seg.build(1,1,n);
    	while (Q--)
    	{
    		scanf("%d%d",&ql,&qr);
    		seg.update(1,ql,qr);
    		printf("%d\n",seg.query(1,ql,qr).ans);
    	}
    	return 0;
    } 
    
  • 相关阅读:
    GL_TRIANGLE_FAN Vs GL_TRIANGLE_STRIP
    Color bleeding与caustics概念解析
    Two path ray tracing与Photon Mapping(粒子跟踪)
    右手定则判断法线方向
    正确使用atoi
    深入探讨透视投影坐标变换
    gluBuild2DMipmaps与glTexImage2D与glGenTexture()函数
    OpenGL纹理贴图流程
    int main( int argc, char ** argv)在VS2008中的配置的一个实例
    c++标准库中vector数组遍历时的用法
  • 原文地址:https://www.cnblogs.com/stoorz/p/13233645.html
Copyright © 2011-2022 走看看