bzoj 1858: [Scoi2010]序列操作(线段树)

1858: [Scoi2010]序列操作

Time Limit: 10 Sec   Memory Limit: 64 MB
Submit: 2171   Solved: 1087
[ Submit][ Status][ Discuss]

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

Source

[ Submit][ Status][ Discuss]


题解:线段树

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define N 500003
using namespace std;
int delta[N],rev[N],tr[N],ls[N],rs[N],a[N],b[N],tr1[N],ls1[N],rs1[N];
int num[N],n,m;
struct data
{
	int tr,ls,rs;
	int l,r;
};
void update(int x,int l,int r)
{
	int mid=(l+r)/2;
	a[x]=a[x<<1]+a[x<<1|1];
	b[x]=b[x<<1]+b[x<<1|1];
	tr[x]=max(tr[x<<1],max(tr[x<<1|1],rs[x<<1]+ls[x<<1|1]));
	tr1[x]=max(tr1[x<<1],max(tr1[x<<1|1],rs1[x<<1]+ls1[x<<1|1]));
	ls[x]=ls[x<<1]+(ls[x<<1]==mid-l+1?ls[x<<1|1]:0);
	rs[x]=rs[x<<1|1]+(rs[x<<1|1]==r-mid?rs[x<<1]:0);
	ls1[x]=ls1[x<<1]+(ls1[x<<1]==mid-l+1?ls1[x<<1|1]:0);
	rs1[x]=rs1[x<<1|1]+(rs1[x<<1|1]==r-mid?rs1[x<<1]:0);
}
void solve(int now,int l,int r,int v)
{
	    if (v==2)  tr1[now]=ls1[now]=rs1[now]=b[now]=0,rev[now]=0,delta[now]=v,
		tr[now]=ls[now]=rs[now]=a[now]=(r-l+1);
		else
		 tr[now]=ls[now]=rs[now]=a[now]=0,rev[now]=0,delta[now]=v,
		 tr1[now]=ls1[now]=rs1[now]=b[now]=(r-l+1);
}
void solve1(int now)
{
	    if (delta[now]&&rev[now])
	 	 rev[now]=0,delta[now]=(delta[now]==1?2:1);
	 	swap(tr[now],tr1[now]);
	 	swap(a[now],b[now]);
	 	swap(ls[now],ls1[now]);
	 	swap(rs[now],rs1[now]);
}
void pushdown(int x,int l,int r)
{
	int mid=(l+r)/2;
	if (delta[x])
	 {
	 	delta[x<<1]=delta[x]; delta[x<<1|1]=delta[x];
	 	solve(x<<1,l,mid,delta[x]); solve(x<<1|1,mid+1,r,delta[x]);
	 	delta[x]=0; rev[x]=0;
	 }
	if (rev[x])
	 {
	 	rev[x<<1]^=1; rev[x<<1|1]^=1;
	 	solve1(x<<1); solve1(x<<1|1);
	 	rev[x]=0;
	 }
}
void build(int now,int l,int r)
{
	if (l==r)
	{
		if(num[l])  tr[now]=ls[now]=rs[now]=a[now]=1;
		else tr1[now]=ls1[now]=rs1[now]=b[now]=1;
		return;
	}
	int mid=(l+r)/2;
	build(now<<1,l,mid);
	build(now<<1|1,mid+1,r);
	update(now,l,r);
}
void qjchange(int now,int l,int r,int ll,int rr,int v)
{
	if (ll<=l&&r<=rr)
	{
		if (v==2)  tr1[now]=ls1[now]=rs1[now]=b[now]=0,rev[now]=0,delta[now]=v,
		tr[now]=ls[now]=rs[now]=a[now]=(r-l+1);
		else
		 tr[now]=ls[now]=rs[now]=a[now]=0,rev[now]=0,delta[now]=v,
		 tr1[now]=ls1[now]=rs1[now]=b[now]=(r-l+1);
		return;
	}
	int mid=(l+r)/2;
	pushdown(now,l,r);
	if (ll<=mid) qjchange(now<<1,l,mid,ll,rr,v);
	if (rr>mid) qjchange(now<<1|1,mid+1,r,ll,rr,v);
	update(now,l,r);
}
void qjrev(int now,int l,int r,int ll,int rr)
{
	if (ll<=l&&r<=rr)
	 {
	 	rev[now]^=1;
	 	if (delta[now]&&rev[now])
	 	{
	 	   rev[now]=0,delta[now]=(delta[now]==1?2:1);
	 	   if (delta[now]==2)  tr1[now]=ls1[now]=rs1[now]=b[now]=0,rev[now]=0,
		     tr[now]=ls[now]=rs[now]=a[now]=(r-l+1);
		    else
		     tr[now]=ls[now]=rs[now]=a[now]=0,rev[now]=0,
		     tr1[now]=ls1[now]=rs1[now]=b[now]=(r-l+1);
	    }
	 	else
	 	{
		 	swap(tr[now],tr1[now]);
		 	swap(a[now],b[now]);
		 	swap(ls[now],ls1[now]);
		 	swap(rs[now],rs1[now]);
	    }
	 	return;
	 }
	int mid=(l+r)/2;
	pushdown(now,l,r);
	if (ll<=mid) qjrev(now<<1,l,mid,ll,rr);
	if (rr>mid) qjrev(now<<1|1,mid+1,r,ll,rr);
	update(now,l,r);
}
int qjsum(int now,int l,int r,int ll,int rr)
{
	if (ll<=l&&r<=rr)  return a[now];
	int mid=(l+r)/2;
	pushdown(now,l,r);
	int ans=0;
	if (ll<=mid) ans+=qjsum(now<<1,l,mid,ll,rr);
	if (rr>mid) ans+=qjsum(now<<1|1,mid+1,r,ll,rr);
	return ans;
}
void clear (data &a)
{
	a.tr=a.ls=a.rs=0;
}
data calc(data a,data b)
{
	data c;
	c.l=min(a.l,b.l); c.r=max(a.r,b.r);
	c.tr=max(a.tr,max(b.tr,a.rs+b.ls));
	c.ls=a.ls+(a.ls==a.r-a.l+1?b.ls:0);
	c.rs=b.rs+(b.rs==b.r-b.l+1?a.rs:0);
	return c;
}
data merge(int now,int l,int r,int ll,int rr)
{
	if (ll<=l&&r<=rr)
	 {
	 	data a; clear(a); a.l=l; a.r=r;
		a.tr=tr[now]; a.ls=ls[now]; a.rs=rs[now];
		return a;
	 }
	int mid=(l+r)/2;
	pushdown(now,l,r);
	data a; clear(a); a.l=max(ll,l); a.r=0;
	bool f=false;
	if (ll<=mid) {
		a=merge(now<<1,l,mid,ll,rr);
		f=true;
	}
	if (rr>mid) {
		data b; clear(b); 
		b=merge(now<<1|1,mid+1,r,ll,rr);
		if (f)  a=calc(a,b);
		else a=b;
	}
	return a;
}
int main()
{
	scanf("%d%d",&n,&m);
	for (int i=1;i<=n;i++)
	 scanf("%d",&num[i]);
	build(1,1,n);
	for (int i=1;i<=m;i++)
	{
		int k,x,y; scanf("%d%d%d",&k,&x,&y); x++; y++;
		if (k<=1)
		 qjchange(1,1,n,x,y,k+1);
		if (k==2)  qjrev(1,1,n,x,y);
		if (k==3)  printf("%d\n",qjsum(1,1,n,x,y));
		if (k==4)  
		{
		  data a=merge(1,1,n,x,y);
		  printf("%d\n",a.tr);
	    }
	}
}



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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值