【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;
} 
原文地址:https://www.cnblogs.com/stoorz/p/13233645.html