BZOJ1858: [Scoi2010]序列操作

1858: [Scoi2010]序列操作

Time Limit: 10 Sec   Memory Limit: 64 MB
Submit: 1031   Solved: 529
[Submit][Status]

Description

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都需要给出回答,聪明的程序员们,你们能帮助他吗?

Input

输入数据第一行包括2个数,n和m,分别表示序列的长度和操作数目 第二行包括n个数,表示序列的初始状态 接下来m行,每行3个数,op, a, b,(0<=op<=4,0<=a<=b<n)表示对于区间[a, b]执行标号为op的操作="" <="" div="" style="font-family: arial, verdana, helvetica, sans-serif;">

Output

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

Sample Input

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

Sample Output

5
2
6
5

HINT

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

题解:
需要维护4种变量:
1.从左端点最大连续的相同数字
2.从右端点最大连续的相同数字
3.区间内最长连续的相同数字
4.区间内存在多少个相同数字(只是为了操作3)、

因为这个题需要把区间所有数字取反,所以需要同时维护0和1的以上四种量,也就是要维护2*4=8个变量

然后延迟标记要有3种:
1.全0覆盖标记
2.全1覆盖标记
3.区间取反标记

pushup的时候:
1.区间中最长连续的相同数字=max(左区间内最长连续的相同数字,右区间内最长连续的相同数字,左区间右端点最大连续的相同数字+右区间左端点最大连续的相同数字)
2.区间从左右端点最大连续相同数字在pushup的时候要注意,如果左区间或右区间全是1或0的话要特判一下

修改或者pushup的时候:
两种覆盖标记最多存在一个。
当下传了一个区间取反标记:若存在着覆盖标记,则直接将覆盖标记对调;若不存在覆盖标记,直接将区间取反标记异或;
当下传了一个覆盖标记:将其他延迟标记全部清0

#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int N=100005;
struct pp {int l,r,c0,c1,ml1,mr1,mx1,ml0,mr0,mx0,len,l1,l0,ln;} T[N*4];
int n,m,a[N];
void pushup(int x)
{
	int lc=x<<1,rc=x<<1|1;
	T[x].ml1=T[lc].ml1;
	T[x].mr1=T[rc].mr1;
	if(T[lc].ml1==T[lc].len) T[x].ml1=T[lc].len+T[rc].ml1;
	if(T[rc].mr1==T[rc].len) T[x].mr1=T[rc].len+T[lc].mr1;
	T[x].ml0=T[lc].ml0;
	T[x].mr0=T[rc].mr0;
	if(T[lc].ml0==T[lc].len) T[x].ml0=T[lc].len+T[rc].ml0;
	if(T[rc].mr0==T[rc].len) T[x].mr0=T[rc].len+T[lc].mr0;
	T[x].mx1=max(T[lc].mr1+T[rc].ml1,max(T[lc].mx1,T[rc].mx1));
	T[x].mx0=max(T[lc].mr0+T[rc].ml0,max(T[lc].mx0,T[rc].mx0));
	T[x].c0=T[lc].c0+T[rc].c0;
	T[x].c1=T[lc].c1+T[rc].c1;
}
int e[2];
void pushdown(int x)
{
	e[0]=x<<1,e[1]=x<<1|1;
	if(T[x].l0)
	for(int i=0;i<=1;i++)
	{
		T[e[i]].ml1=T[e[i]].mr1=T[e[i]].mx1=T[e[i]].c1=0;
		T[e[i]].ml0=T[e[i]].mr0=T[e[i]].mx0=T[e[i]].c0=T[e[i]].len;
		T[e[i]].l0=1;
		T[e[i]].l1=T[e[i]].ln=0;
	}
	if(T[x].l1)
	for(int i=0;i<=1;i++)
	{
		T[e[i]].ml0=T[e[i]].mr0=T[e[i]].mx0=T[e[i]].c0=0;
		T[e[i]].ml1=T[e[i]].mr1=T[e[i]].mx1=T[e[i]].c1=T[e[i]].len;
		T[e[i]].l1=1;
		T[e[i]].l0=T[e[i]].ln=0;
	}
	if(T[x].ln)
	for(int i=0;i<=1;i++)
	{
		swap(T[e[i]].ml1,T[e[i]].ml0);
		swap(T[e[i]].mr1,T[e[i]].mr0);
		swap(T[e[i]].mx1,T[e[i]].mx0);
		swap(T[e[i]].c1,T[e[i]].c0);
		if(T[e[i]].l1) T[e[i]].l0=1,T[e[i]].l1=0;
		else if(T[e[i]].l0) T[e[i]].l1=1,T[e[i]].l0=0;
		else T[e[i]].ln^=1;
	}
	T[x].l1=T[x].l0=T[x].ln=0;
}
void build(int x,int l,int r)
{
	T[x].l=l,T[x].r=r;
	T[x].len=T[x].r-T[x].l+1;
	if(l==r)
	{
		if(!a[l]) T[x].ml0=T[x].mr0=T[x].mx0=T[x].c0=1;
		else T[x].ml1=T[x].mr1=T[x].mx1=T[x].c1=1;
		return;
	}
	int mid=(l+r)>>1;
	build(x<<1,l,mid);
	build(x<<1|1,mid+1,r);
	pushup(x);
}
void Modify(int x,int l,int r,int v)
{
	if(T[x].l==l&&T[x].r==r)
	{
		if(v==3)
		{
			swap(T[x].ml1,T[x].ml0);
			swap(T[x].mr1,T[x].mr0);
			swap(T[x].mx1,T[x].mx0);
			swap(T[x].c1,T[x].c0);
			if(T[x].l1) T[x].l0=1,T[x].l1=0;
			else if(T[x].l0) T[x].l1=1,T[x].l0=0;
			else T[x].ln^=1;
		}
		if(v==1)//????0
		{
			T[x].ml1=T[x].mr1=T[x].mx1=T[x].c1=0;
			T[x].ml0=T[x].mr0=T[x].mx0=T[x].c0=T[x].len;
			T[x].l0=1;
			T[x].l1=T[x].ln=0;
		}
		if(v==2)//????1
		{
			T[x].ml0=T[x].mr0=T[x].mx0=T[x].c0=0;
			T[x].ml1=T[x].mr1=T[x].mx1=T[x].c1=T[x].len;
			T[x].l1=1;
			T[x].l0=T[x].ln=0;
		}
		return;
	}
	if(T[x].l1||T[x].l0||T[x].ln) pushdown(x);
	int mid=(T[x].l+T[x].r)>>1;
	if(r<=mid) Modify(x<<1,l,r,v);
	else if(l>mid) Modify(x<<1|1,l,r,v);
	else Modify(x<<1,l,mid,v),Modify(x<<1|1,mid+1,r,v);
	pushup(x);
}
int QueryA(int x,int l,int r)
{
	if(T[x].l==l&&T[x].r==r) return T[x].c1;
	if(T[x].l1||T[x].l0||T[x].ln) pushdown(x);
	int mid=(T[x].l+T[x].r)>>1;
	if(r<=mid) return QueryA(x<<1,l,r);
	else if(l>mid) return QueryA(x<<1|1,l,r);
	else return QueryA(x<<1,l,mid)+QueryA(x<<1|1,mid+1,r);
}
int o,xx,yy;
int QueryC(int x,int l,int r)
{
	if(T[x].l==l&&T[x].r==r) return T[x].mx1;
	if(T[x].l1||T[x].l0||T[x].ln) pushdown(x);
	int mid=(T[x].l+T[x].r)>>1;
	if(r<=mid) return QueryC(x<<1,l,r);
	else if(l>mid) return QueryC(x<<1|1,l,r);
	else return max(min(yy,T[x<<1|1].ml1+mid)-max(xx,mid-T[x<<1].mr1+1)+1,max(QueryC(x<<1,l,mid),QueryC(x<<1|1,mid+1,r)));
}
int main()
{
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++) scanf("%d",&a[i]);
	build(1,1,n);
	for(int i=1;i<=m;i++)
	{
		scanf("%d%d%d",&o,&xx,&yy);
		xx++,yy++;
		if(o==0) Modify(1,xx,yy,1);
		if(o==1) Modify(1,xx,yy,2);
		if(o==2) Modify(1,xx,yy,3);
		if(o==3) printf("%d\n",QueryA(1,xx,yy));
		if(o==4) printf("%d\n",QueryC(1,xx,yy));
	}
}


  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值