【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,只是查询答案显然无法做到最值的合并与比较,那么,我们就直接询问线段树该节点的状态,直接返回一棵临时的线段树,就可以知道连续的最值了。这里要用到线段树的合并,也算一项技能,可以多看看。
代码如下:
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; }
相关文章推荐
- 【BZOJ 1858】 [Scoi2010]序列操作
- BZOJ 1858 [Scoi2010]序列操作 线段树
- BZOJ 1858: [Scoi2010]序列操作 [线段树]
- bzoj 1858: [Scoi2010]序列操作
- BZOJ1858: [Scoi2010]序列操作
- BZOJ 1858 SCOI2010 序列操作 线段树
- 【BZOJ 1858】【SCOI 2010】序列操作【区间线段树】
- 【BZOJ1858】[Scoi2010]序列操作 线段树
- bzoj 1858: [Scoi2010]序列操作 -- 线段树
- BZOJ1858[Scoi2010]序列操作 题解
- bzoj1858: [Scoi2010]序列操作
- bzoj1858【scoi2010】序列操作
- 【bzoj1858】[Scoi2010]序列操作 线段树区间合并
- 【bzoj1858】【Scoi2010】序列操作【位运算】【卡常大法好】
- BZOJ 1858: [Scoi2010]序列操作( 线段树 )
- bzoj 1858: [Scoi2010] 序列操作 题解
- hdu3397 Sequence operation 线段树区间更新&&bzoj1858: [Scoi2010]序列操作
- 【分块】bzoj1858 [Scoi2010]序列操作
- bzoj1858 [Scoi2010]序列操作
- BZOJ 1858 SCOI 2010 序列操作