您的位置:首页 > 其它

【BZOJ1858】【SCOI2010】序列操作(线段树+合并)

2017-03-27 17:56 357 查看
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。

题解:

本来以为是一道比较简单的线段树打打标记就过了,但是询问4好难写。。。

其他的比较简单,就是一些tag,rev标记。主要说一下询问4。

我们需要维护下列东西:

1.1的个数;(sum1)

2.从头开始1的连续的个数;(l1)

3.从尾开始1的连续的个数(2、3两个是为了维护连续最大值而存在的);(r1)

4.最大的连续的1的个数;(mx1)

5.从头开始0的连续的个数;(l0)

6.从尾开始0的连续的个数;(l1)

7.最大的连续的0的个数;(mx0)

8.0的个数;(sum0)

对于询问4,只是查询答案显然无法做到最值的合并与比较,那么,我们就直接询问线段树该节点的状态,直接返回一棵临时的线段树,就可以知道连续的最值了。这里要用到线段树的合并,也算一项技能,可以多看看。

代码如下:

#include<iostream>
#include<stdio.h>
#include<algorithm>
#include<string.h>
#include<math.h>
#define ll long long
#define inf 0x7f7f7f7f
#define N 100005
#define ls (rt<<1)
#define rs (rt<<1|1)
#define mid (l+r>>1)
using namespace std;
struct seg
{
int l,r;
int l0,l1,r0,r1,mx0,mx1,sum0,sum1;
int rev,c,full;
}t[N*3];
void color(int rt,int c)
{
t[rt].full=c;t[rt].rev=0;
int len=t[rt].r-t[rt].l+1;
if(!c)
{
t[rt].sum0=t[rt].l0=t[rt].r0=t[rt].mx0=len;
t[rt].sum1=t[rt].l1=t[rt].r1=t[rt].mx1=0;
}
else
{
t[rt].sum0=t[rt].l0=t[rt].r0=t[rt].mx0=0;
t[rt].sum1=t[rt].l1=t[rt].r1=t[rt].mx1=len;
}
}
void rev(int rt)
{
swap(t[rt].sum0,t[rt].sum1);
swap(t[rt].l0,t[rt].l1);
swap(t[rt].r0,t[rt].r1);
swap(t[rt].mx0,t[rt].mx1);
if(~t[rt].full) t[rt].full^=1;
}
seg merge(seg a,seg b)
{
seg tmp;
tmp.l=a.l,tmp.r=b.r;
tmp.rev=0,tmp.c=-1;
tmp.l0=a.l0,tmp.l1=a.l1,tmp.r0=b.r0,tmp.r1=b.r1;
tmp.mx0=max(a.mx0,b.mx0),tmp.mx1=max(a.mx1,b.mx1);
tmp.mx0=max(tmp.mx0,a.r0+b.l0),tmp.mx1=max(tmp.mx1,a.r1+b.l1);
tmp.sum0=a.sum0+b.sum0,tmp.sum1=a.sum1+b.sum1;
if(a.full==0) tmp.l0=a.mx0+b.l0;
else if(a.full==1) tmp.l1=a.mx1+b.l1;
if(b.full==0) tmp.r0=b.mx0+a.r0;
else if(b.full==1) tmp.r1=b.mx1+a.r1;
if(a.full==b.full) tmp.full=a.full;
else tmp.full=-1;
return tmp;
}
void pushup(int rt){t[rt]=merge(t[ls],t[rs]);}
void pushdown(int rt)
{
if(t[rt].l==t[rt].r) return;
if(~t[rt].c)
{
t[ls].c=t[rs].c=t[rt].c;
color(ls,t[rt].c),color(rs,t[rt].c);
t[rt].c=-1;
}
if(t[rt].rev)
{
t[ls].rev^=1;t[rs].rev^=1;
rev(ls),rev(rs);
t[rt].rev=0;
}
}
void build(int rt,int l,int r)
{
t[rt].l=l,t[rt].r=r;
t[rt].c=-1;
if(l==r)
{
scanf("%d",&t[rt].full);
if(t[rt].full) t[rt].l1=t[rt].r1=t[rt].mx1=t[rt].sum1=1;
else t[rt].l0=t[rt].r0=t[rt].mx0=t[rt].sum0=1;
return ;
}
build(ls,l,mid);build(rs,mid+1,r);
pushup(rt);
}
void change(int rt,int L,int R,int v)
{
pushdown(rt);
int l=t[rt].l,r=t[rt].r;
if(l==L && r==R)
{
color(rt,v);
t[rt].c=v;
return ;
}
if(R<=mid) change(ls,L,R,v);
else if(L>mid) change(rs,L,R,v);
else{change(ls,L,mid,v);change(rs,mid+1,R,v);}
pushup(rt);
}
void rever(int rt,int L,int R)
{
pushdown(rt);
int l=t[rt].l,r=t[rt].r;
if(l==L && r==R)
{
rev(rt);
t[rt].rev=1;
return ;
}
if(R<=mid) rever(ls,L,R);
else if(L>mid) rever(rs,L,R);
else{rever(ls,L,mid);rever(rs,mid+1,R);}
pushup(rt);
}
int getsum(int rt,int L,int R)
{
pushdown(rt);
int l=t[rt].l,r=t[rt].r;
if(l==L && r==R) return t[rt].sum1;
if(R<=mid) return getsum(ls,L,R);
else if(L>mid) return getsum(rs,L,R);
else return getsum(ls,L,mid)+getsum(rs,mid+1,R);
}
seg ask(int rt,int L,int R)
{
pushdown(rt);
int l=t[rt].l,r=t[rt].r;
if(l==L && r==R) return t[rt];
if(R<=mid) return ask(ls,L,R);
else if(L>mid) return ask(rs,L,R);
else return merge(ask(ls,L,mid),ask(rs,mid+1,R));
}
int main()
{
int n,m,op,a,b;
scanf("%d%d",&n,&m);
build(1,1,n);
for(int i=1;i<=m;i++)
{
scanf("%d%d%d",&op,&a,&b);
a++,b++;
switch(op)
{
case 0:change(1,a,b,0);break;
case 1:change(1,a,b,1);break;
case 2:rever(1,a,b);break;
case 3:printf("%d\n",getsum(1,a,b));break;
case 4:printf("%d\n",ask(1,a,b).mx1);break;
}
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  线段树 省选