【BZOJ1858】[Scoi2010]序列操作 线段树

线段树裸(shen)题……

题意:对01串进行五种操作:0、清零;1、清一;2、取反(flip);3、询问区间内'1'的个数;4、询问区间内最多的连续的'1'的个数。

果然,看完前四个操作,我感觉我看到了一个 bitset 裸题~。既然有了第五个操作,则改用线段树:

对于每一段区间,维护下列信息:

左/右端点数值 leftnum/rightnum(0/1);

左/右起最长连续元素个数 llen/rlen(0/1不限,关于区间属性使用leftnum/rightnum判断);

区间内最长连续的0/1的个数 len[][0]/len[][1];

区间内1的数量 sum;

清数值/取反标记 lazy_num/lazy_flip

每一个节点的leftnum/rightnum和子节点信息相同,llen、rlen、len[][0]\len[][1]信息可由其子节点信息分类讨论得到。

每一个取反操作需swap(len[pos][0],len[pos][1]),llen和rlen不需更新。

另外,只有注意细节,此题方能AC~

这是我迄今为止除交表外代码最长的一题~~我是蒟蒻沙茶~~

[Scoi2010]序列操作 C++代码实现:

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
#define lson pos<<1
#define rson pos<<1|1
#define N 100010
int n,m;
int a[N];
int leftnum[4*N],rightnum[4*N],llen[4*N],rlen[4*N],len[4*N][2],sum[4*N],lazy_num[4*N],lazy_flip[4*N];
inline void maintain(int pos,int l,int r)
{
	int mid=(l+r)>>1;
	sum[pos]=sum[lson]+sum[rson];
	leftnum[pos]=leftnum[lson];
	rightnum[pos]=rightnum[rson];
	llen[pos]=(llen[lson]==mid-l+1&&rightnum[lson]==leftnum[rson])?llen[lson]+llen[rson]:llen[lson];
	rlen[pos]=(rlen[rson]==r-mid&&leftnum[rson]==rightnum[lson])?rlen[rson]+rlen[lson]:rlen[rson];
	len[pos][0]=max(len[lson][0],len[rson][0]);
	len[pos][1]=max(len[lson][1],len[rson][1]);
	if(rightnum[lson]==leftnum[rson]) len[pos][rightnum[lson]]=max(len[pos][rightnum[lson]],rlen[lson]+llen[rson]);
}
inline void lazy(int pos,int l,int r)
{
	int mid=(l+r)>>1;
	if(lazy_num[pos]>=0)
	{
		lazy_num[lson]=lazy_num[rson]=lazy_num[pos];
		lazy_flip[lson]=lazy_flip[rson]=0;
		leftnum[lson]=rightnum[lson]=leftnum[rson]=rightnum[rson]=lazy_num[pos];
		llen[lson]=rlen[lson]=len[lson][lazy_num[pos]]=mid-l+1;llen[rson]=rlen[rson]=len[rson][lazy_num[pos]]=r-mid;
		len[lson][lazy_num[pos]^1]=len[rson][lazy_num[pos]^1]=0;
		sum[lson]=(mid-l+1)*lazy_num[pos];sum[rson]=(r-mid)*lazy_num[pos];
		lazy_num[pos]=-1;
	}
	if(lazy_flip[pos])
	{
		lazy_flip[pos]=0;
		if(lazy_num[lson]>=0) lazy_num[lson]^=1;
		else lazy_flip[lson]^=1;
		if(lazy_num[rson]>=0) lazy_num[rson]^=1;
		else lazy_flip[rson]^=1;
		leftnum[lson]^=1;rightnum[lson]^=1;
		leftnum[rson]^=1;rightnum[rson]^=1;
		swap(len[lson][0],len[lson][1]);
		swap(len[rson][0],len[rson][1]);
		sum[lson]=(mid-l+1-sum[lson]);
		sum[rson]=(r-mid-sum[rson]);
	}
}
void build(int pos,int l,int r)
{
	lazy_num[pos]=-1;
	if(l==r)
	{
		leftnum[pos]=rightnum[pos]=sum[pos]=a[l];
		llen[pos]=rlen[pos]=1;
		len[pos][a[l]]=1;
		return;
	}
	int mid=(l+r)>>1;
	build(lson,l,mid);
	build(rson,mid+1,r);
	maintain(pos,l,r);
}
void clear(int pos,int l,int r,int x,int y,int z)
{
	if(x<=l&&r<=y)
	{
		lazy_flip[pos]=0;
		leftnum[pos]=rightnum[pos]=lazy_num[pos]=z;
		llen[pos]=rlen[pos]=len[pos][z]=r-l+1;
		len[pos][z^1]=0;
		sum[pos]=(r-l+1)*z;
		return;
	}
	if(lazy_num[pos]>=0||lazy_flip[pos])
		lazy(pos,l,r);
	int mid=(l+r)>>1;
	if(y<=mid) clear(lson,l,mid,x,y,z);
	else if(x>mid) clear(rson,mid+1,r,x,y,z);
	else clear(lson,l,mid,x,y,z),clear(rson,mid+1,r,x,y,z);
	maintain(pos,l,r);
}
void flip(int pos,int l,int r,int x,int y)
{
	if(x<=l&&r<=y)
	{
		if(lazy_num[pos]>=0) lazy_num[pos]^=1;
		else lazy_flip[pos]^=1;
		leftnum[pos]^=1;
		rightnum[pos]^=1;
		swap(len[pos][0],len[pos][1]);
		sum[pos]=(r-l+1-sum[pos]);
		return;
	}
	if(lazy_num[pos]>=0||lazy_flip[pos])
		lazy(pos,l,r);
	int mid=(l+r)>>1;
	if(y<=mid) flip(lson,l,mid,x,y);
	else if(x>mid) flip(rson,mid+1,r,x,y);
	else flip(lson,l,mid,x,y),flip(rson,mid+1,r,x,y);
	maintain(pos,l,r);
}
int query_sum(int pos,int l,int r,int x,int y)
{
	if(x<=l&&r<=y) return sum[pos];
	if(lazy_num[pos]>=0||lazy_flip[pos])
		lazy(pos,l,r);
	int mid=(l+r)>>1;
	if(y<=mid) return query_sum(lson,l,mid,x,y);
	if(x>mid) return query_sum(rson,mid+1,r,x,y);
	return query_sum(lson,l,mid,x,y)+query_sum(rson,mid+1,r,x,y);
}
int query_llen(int pos,int l,int r,int x)
{
	if(r<=x) return llen[pos];
	if(lazy_num[pos]>=0||lazy_flip[pos])
		lazy(pos,l,r);
	int mid=(l+r)>>1;
	if(x>mid) return (llen[lson]==mid-l+1&&rightnum[lson]==leftnum[rson])?llen[lson]+query_llen(rson,mid+1,r,x):llen[lson];
	return query_llen(lson,l,mid,x);
}
int query_rlen(int pos,int l,int r,int x)
{
	if(x<=l) return rlen[pos];
	if(lazy_num[pos]>=0||lazy_flip[pos])
		lazy(pos,l,r);
	int mid=(l+r)>>1;
	if(x<=mid) return (rlen[rson]==r-mid&&leftnum[rson]==rightnum[lson])?rlen[rson]+query_rlen(lson,l,mid,x):rlen[rson];
	return query_rlen(rson,mid+1,r,x);
}
int query_len(int pos,int l,int r,int x,int y)
{
	if(x<=l&&r<=y) return len[pos][1];
	if(lazy_num[pos]>=0||lazy_flip[pos])
		lazy(pos,l,r);
	int mid=(l+r)>>1;
	if(y<=mid) return query_len(lson,l,mid,x,y);
	if(x>mid) return query_len(rson,mid+1,r,x,y);
	if(rightnum[lson]==1&&leftnum[rson]==1)
		return max(query_rlen(lson,l,mid,x)+query_llen(rson,mid+1,r,y),max(query_len(lson,l,mid,x,y),query_len(rson,mid+1,r,x,y)));
	return max(query_len(lson,l,mid,x,y),query_len(rson,mid+1,r,x,y));
}
int main()
{
	cin>>n>>m;
	for(int i=1;i<=n;i++)
		scanf("%d",&a[i]);
	build(1,1,n);
	for(int opt,x,y,i=1;i<=m;i++)
	{
		scanf("%d%d%d",&opt,&x,&y);
		x++;y++;
		if(opt==0)
			clear(1,1,n,x,y,0);
		else if(opt==1)
			clear(1,1,n,x,y,1);
		else if(opt==2)
			flip(1,1,n,x,y);
		else if(opt==3)
			printf("%d\n",query_sum(1,1,n,x,y));
		else printf("%d\n",query_len(1,1,n,x,y));
	}
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值