BZOJ 1858 [Scoi2010]序列操作 线段树

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)

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


比较简单的用线段树维护的题目。
前面几个都比较简单。

反正都是下放一个tag,细节注意一下就好了。
还有就是要注意2操作的优先级应该低于0,1操作!
0,1操作更新完后就把2操作的标记清零。

2操作,1和0互换,只要把它们的信息也互换即可。
而4操作比较麻烦,不过BZOJ 1500
其中的最后一个要求有些类似。
我们也是记录左端连续个数lx,右端rx,以及中间最长连续的mx。
然后维护的时候有一些不同,不过只要分类讨论即可。

下文假设lx,rx,mx均指1的连续长度。
注意一下比如1110中,11的lx为2,10的lx为1。
类似于这种样例要注意特判。
具体的维护简单想一下就好了……还是比较简单的。。

#include<bits/stdc++.h>
#define pr(a,b,c) {a,b,c}
using namespace std;
int read(){
    int x=0,f=1;char ch=getchar();
    while (ch<'0' || ch>'9'){if (ch=='-') f=-1;ch=getchar();}
    while (ch>='0' && ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}
const int 
	MAX=100005;
int n,m;
struct Segment{
	int Num[2],lx[2],rx[2],mx[2];
	int TAG;
	bool rev,tag;
}tr[MAX<<2];
struct Query2{
	int lx,mx,rx;
};
void up(int u,int L,int R){
	int l=u<<1,r=u<<1|1,mid=(L+R)>>1;
	for (int i=0;i<2;i++){
		tr[u].Num[i]=tr[l].Num[i]+tr[r].Num[i];
		tr[u].mx[i]=max(max(tr[r].mx[i],tr[l].rx[i]+tr[r].lx[i]),tr[l].mx[i]);
		tr[u].lx[i]=tr[l].lx[i];
		if (tr[l].lx[i]==mid-L+1) tr[u].lx[i]+=tr[r].lx[i];
		tr[u].rx[i]=tr[r].rx[i];
		if (tr[r].rx[i]==R-mid) tr[u].rx[i]+=tr[l].rx[i];
	}
}
void Swap(int id){
	swap(tr[id].Num[0],tr[id].Num[1]);
	swap(tr[id].lx[0],tr[id].lx[1]);
	swap(tr[id].rx[0],tr[id].rx[1]);
	swap(tr[id].mx[0],tr[id].mx[1]);
}
void Tag(int id,int num,int l,int r){
	tr[id].Num[num]=r-l+1;
	tr[id].Num[num^1]=0;
	tr[id].lx[0]=tr[id].rx[0]=tr[id].mx[0]=(r-l+1)*(num==0);
	tr[id].lx[1]=tr[id].rx[1]=tr[id].mx[1]=(r-l+1)*(num==1);
	tr[id].TAG=num;
	tr[id].tag=1;
	tr[id].rev=0;
}
void down(int u,int L,int R){
	if (tr[u].tag){
		int l=u<<1,r=u<<1|1,mid=(L+R)>>1;
		Tag(l,tr[u].TAG,L,mid);
		Tag(r,tr[u].TAG,mid+1,R);
		tr[u].tag=0;
	}
	if (tr[u].rev){
		int l=u<<1,r=u<<1|1;
		tr[l].rev^=1,Swap(l);
		tr[r].rev^=1,Swap(r);
		tr[u].rev=0;
	}
}
void updateAll(int id,int l,int r,int gl,int gr,int num){
	if (l>=gl && r<=gr){
		Tag(id,num,l,r);
		return;
	}
	down(id,l,r);
	int mid=(l+r)>>1;
	if (gr<=mid) updateAll(id<<1,l,mid,gl,gr,num); else
	if (gl>mid) updateAll(id<<1|1,mid+1,r,gl,gr,num);
		else{
			updateAll(id<<1,l,mid,gl,mid,num);
			updateAll(id<<1|1,mid+1,r,mid+1,gr,num);
		}
	up(id,l,r);
}
void reverseAll(int id,int l,int r,int gl,int gr){
	if (l>=gl && r<=gr){
		tr[id].rev^=1;
		Swap(id);
		return;
	}
	down(id,l,r);
	int mid=(l+r)>>1;
	if (gr<=mid) reverseAll(id<<1,l,mid,gl,gr); else
	if (gl>mid) reverseAll(id<<1|1,mid+1,r,gl,gr);
		else{
			reverseAll(id<<1,l,mid,gl,mid);
			reverseAll(id<<1|1,mid+1,r,mid+1,gr);
		}
	up(id,l,r);
}
int query1(int id,int l,int r,int gl,int gr){
	if (l>=gl && r<=gr) return tr[id].Num[1];
	down(id,l,r);
	int mid=(l+r)>>1,t1;
	if (gr<=mid) t1=query1(id<<1,l,mid,gl,gr); else
	if (gl>mid) t1=query1(id<<1|1,mid+1,r,gl,gr);
		else
		 t1=query1(id<<1,l,mid,gl,mid)+query1(id<<1|1,mid+1,r,mid+1,gr);
	return t1;
}
Query2 query2(int id,int l,int r,int gl,int gr){
	if (l>=gl && r<=gr) return (Query2){tr[id].lx[1],tr[id].mx[1],tr[id].rx[1]};
	down(id,l,r);
	int mid=(l+r)>>1;
	Query2 t1={0,0,0},t2={0,0,0};
	if (gr<=mid) t1=query2(id<<1,l,mid,gl,gr); else
	if (gl>mid) t2=query2(id<<1|1,mid+1,r,gl,gr);
		else
		 t1=query2(id<<1,l,mid,gl,mid),
		 t2=query2(id<<1|1,mid+1,r,mid+1,gr);
	if (t1.lx==mid-l+1) t1.lx+=t2.lx;
	if (t2.rx==r-mid) t2.rx+=t1.rx;
	return (Query2){t1.lx,max(max(t1.mx,t2.mx),t1.rx+t2.lx),t2.rx};
}
int main(){
	n=read(),m=read();
	for (int i=1;i<=n;i++)
		updateAll(1,1,n,i,i,read()); 
	int opt,a,b;
	while (m--){
		opt=read(),a=read(),b=read();
		a++,b++;
		if (!opt) updateAll(1,1,n,a,b,0);
		if (opt==1) updateAll(1,1,n,a,b,1);
		if (opt==2) reverseAll(1,1,n,a,b);
		if (opt==3) printf("%d\n",query1(1,1,n,a,b));
		if (opt==4) printf("%d\n",query2(1,1,n,a,b).mx);
	}
	return 0;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值