[BZOJ 1858] 序列操作(真·线段树大模板)

·题目描述

lxhgww最近收到了一个01序列,序列里面包含了n个数,这些数要么是0,要么是1,现在对于这个序列有五种变换操作和询问操作:

0 a b 把[a,b]区间内的所有数全变成0

1 a b 把[a,b]区间内的所有数全变成1

2 a b 把[a,b]区间内的所有数全部取反,也就是说把所有的0变成1,把所有的1变成0

3 a b 询问[a,b]区间内总共有多少个1

4 a b 询问[a,b]区间内最多有多少个连续的1

对于每一种询问操作,lxhgww都需要给出回答,聪明的程序员们,你们能帮助他吗?(不能啊w(゚Д゚)w!!!)

·输入格式

输入数据第一行包括2个数,n和m,分别表示序列的长度和操作数目。

第二行包括n个数,表示序列的初始状态 接下来m行,每行3个数,op,a,b,(0≤op≤4,0≤a≤b)

·输出格式

对于每一个询问操作,输出一行,包括1个数,表示其对应的答案

·样例输入

10 10
0 0 0 1 1 0 1 0 1 1
1 0 2
3 0 5
2 2 2
4 0 4
0 3 6
2 3 7
4 2 8
1 0 5
0 5 6
3 3 9

·样例输出

5
2
6
5

·数据范围

对于30%的数据,1≤n,m≤1000
对于100%的数据,1≤n,m≤100000

题解:

不得不说,这道题真的是烦。一看见这道题就想到曾经数次打超长程序无限调试的经历Σ(っ °Д °;)っ。果不其然,这次的程序再一次刷新了我OI生涯中的最长程序纪录。

不多说了,这题就是对每个节点记录几个信息:\(LSum[x]\)为从左端点开始的最长的\(0\)\(1\)个数,\(RSum[x]\)同理,而\(Sum[x]\)是该节点所代表的区间内\(0\)\(1\)的和,\(len[x]\)就代表了这个区间内连续多少个\(0\)\(1\)

再考虑修改操作,对于操作\(3\),我们可以记录一个\(cover\)值,代表这个节点是否被\(0\)\(1\)覆盖,然后在标记下传的时候进行维护。而对于操作\(4\),我们则是选择再次记录一个\(rev\)值,表示这个区间进行多少次翻转,翻转\(2\)次可以视为不翻转。

PS:我做这题+调试达到快5小时,我实在是蒟蒻啊。。。。。。

贴代码

#include <ctype.h>
#include <stdio.h>
#include <iostream>
#define Re register int
using namespace std;

struct SegmentTree{
	int cover,rev,len[2],Sum[2];
	int LSum[2],RSum[2];
}T[500005];
int N,M,A[100005],opt,a,b;

inline int read()
{
	int x=0,w=0; char ch=0;
	while (!isdigit(ch)) w|=ch=='-',ch=getchar();
	while (isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
	return w?-x:x;
}
inline int max(int a,int b) {return a>b?a:b;}
inline int min(int a,int b) {return a<b?a:b;}
inline void swap(int &a,int &b) {a^=b; b^=a; a^=b;}
void PushUp(int id,int l,int r,int mid)
{
	int ls=id*2,rs=id*2+1;
	for (int i=0; i<2; ++i)
	{
		T[id].LSum[i]=(T[ls].LSum[i]==mid-l+1)?
			T[ls].LSum[i]+T[rs].LSum[i]:T[ls].LSum[i];
		T[id].RSum[i]=(T[rs].RSum[i]==r-mid)?
			T[rs].RSum[i]+T[ls].RSum[i]:T[rs].RSum[i];
		T[id].len[i]=max(T[ls].RSum[i]+T[rs].LSum[i],
			max(T[ls].len[i],T[rs].len[i]));
		T[id].Sum[i]=T[ls].Sum[i]+T[rs].Sum[i];
	}
}
inline void PushDown(int id,int l,int r,int mid)
{
	if (!T[id].rev&&T[id].cover==-1) return;
	if (l!=r)
	for (int son=id*2; son<=id*2+1; ++son)
	{
		if (T[id].cover!=-1)
		{
			T[son].cover=T[id].cover; T[son].rev=0; T[son].Sum[T[id].cover^1]=0;
			T[son].Sum[T[id].cover]=(son==id*2)?mid-l+1:r-mid;
			T[son].len[T[id].cover]=T[son].LSum[T[id].cover]=T[son].RSum[T[id].cover]=(son==id*2)?mid-l+1:r-mid;
			T[son].len[T[id].cover^1]=T[son].LSum[T[id].cover^1]=T[son].RSum[T[id].cover^1]=0;
		}
		if (T[id].rev)
		{
			T[son].rev^=T[id].rev;
			swap(T[son].len[0],T[son].len[1]);
			swap(T[son].LSum[0],T[son].LSum[1]);
			swap(T[son].RSum[0],T[son].RSum[1]);
			swap(T[son].Sum[0],T[son].Sum[1]);
		}
	}
	T[id].rev=0; T[id].cover=-1;
}
void Build(int id,int l,int r)
{
	if (l==r)
	{
		T[id].cover=-1; T[id].rev=0; T[id].Sum[A[l]]=1;
		T[id].len[A[l]]=1; T[id].LSum[A[l]]=T[id].RSum[A[l]]=1;
		return;
	}
	int mid=(l+r)>>1; T[id].cover=-1;
	Build(id*2,l,mid); Build(id*2+1,mid+1,r);
	PushUp(id,l,r,mid);
}
void Modify(int id,int l,int r,int L,int R,int c)
{
	if (L<=l&&r<=R)
	{
		T[id].cover=c; T[id].rev=0;
		T[id].Sum[c]=r-l+1; T[id].Sum[c^1]=0;
		T[id].len[c]=r-l+1; T[id].len[c^1]=0;
		T[id].LSum[c]=r-l+1; T[id].LSum[c^1]=0;
		T[id].RSum[c]=r-l+1; T[id].RSum[c^1]=0;
		return;
	}
	int mid=(l+r)>>1; PushDown(id,l,r,mid);
	if (L<=mid) Modify(id*2,l,mid,L,R,c);
	if (mid<R) Modify(id*2+1,mid+1,r,L,R,c);
	PushUp(id,l,r,mid);
}
void Reverse(int id,int l,int r,int L,int R)
{
	if (L<=l&&r<=R)
	{
		T[id].rev^=1;
		swap(T[id].Sum[0],T[id].Sum[1]);
		swap(T[id].len[0],T[id].len[1]);
		swap(T[id].LSum[0],T[id].LSum[1]);
		swap(T[id].RSum[0],T[id].RSum[1]);
		return;
	}
	int mid=(l+r)>>1; PushDown(id,l,r,mid);
	if (L<=mid) Reverse(id*2,l,mid,L,R);
	if (mid<R) Reverse(id*2+1,mid+1,r,L,R);
	PushUp(id,l,r,mid);
}
int QuerySum(int id,int l,int r,int L,int R)
{
	if (L<=l&&r<=R) return T[id].Sum[1];
	int mid=(l+r)>>1,ret=0; PushDown(id,l,r,mid);
	if (L<=mid) ret+=QuerySum(id*2,l,mid,L,R);
	if (mid<R) ret+=QuerySum(id*2+1,mid+1,r,L,R);
	return ret;
}
int QueryLen(int id,int l,int r,int L,int R)
{
	if (L<=l&&r<=R) return T[id].len[1];
	int mid=(l+r)>>1,ret=0; PushDown(id,l,r,mid);
	if (L<=mid) ret=max(ret,QueryLen(id*2,l,mid,L,R));
	if (mid<R) ret=max(ret,QueryLen(id*2+1,mid+1,r,L,R));
	return max(ret,min(mid-L+1,T[id*2].RSum[1])+min(R-mid,T[id*2+1].LSum[1]));
}
int main(int argc, char const *argv[])
{
	N=read(),M=read();
	for (Re i=1; i<=N; ++i) A[i]=read();
	Build(1,1,N);
	for (Re i=1; i<=M; ++i)
	{
		opt=read(),a=read()+1,b=read()+1;
		switch (opt)
		{
			case 0:case 1:Modify(1,1,N,a,b,opt); break;
			case 2: Reverse(1,1,N,a,b); break;
			case 3:	printf("%d\n",QuerySum(1,1,N,a,b)); break;
			case 4: printf("%d\n",QueryLen(1,1,N,a,b)); break;
		}
	}
	return 0;
}
posted @ 2018-08-24 01:18  Alkri  阅读(183)  评论(4编辑  收藏  举报