[BZOJ 1858][Scoi2010]序列操作(线段树)
2017-03-03 20:34
295 查看
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<=bOutput
对于每一个询问操作,输出一行,包括1个数,表示其对应的答案Sample Input
10 100 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
52
6
5
HINT
对于30%的数据,1<=n, m<=1000对于100%的数据,1<=n, m<=100000
Solution
啊为什么调了那么长时间…后来发现是push_down操作给子节点标lazy的时候忘记把它们的rev标记去掉了 泪
线段记录区间里1和0的个数、最长连续的1和0的个数、左端连续的1和0的个数、右端连续的1和0的个数,然后记录一个lazy标记和rev标记(取反)。
取反操作的时候遇到lazy标记可以直接对lazy取反,标记lazy的时候要记得把rev去掉
那个最长连续1的询问函数直接返回了一个结构体,合并操作和线段树的更新差不多,具体实现看代码
感觉我没有办法写出优美的代码,不知道为什么代码长度这么长= =
#include<iostream> #include<cstdio> #include<cstring> #include<queue> #include<assert.h> #define Max(a,b) (a>b?a:b) #define Min(a,b) (a<b?a:b) #define mid(a,b) ((a+b)>>1) #define MAXN 100005 using namespace std; int n,m; int x[MAXN],ans; struct Node{ int l,r,siz; int num1,lnum1,rnum1,maxnum1; int num0,lnum0,rnum0,maxnum0; int lazy,rev; }t[MAXN*4]; Node operator + (const Node& a,const Node& b) { Node ans; ans.lnum0=a.lnum0; if(a.lnum0==a.siz) ans.lnum0=a.siz+b.lnum0; ans.lnum1=a.lnum1; if(a.lnum1==a.siz) ans.lnum1=a.siz+b.lnum1; ans.rnum0=b.rnum0; if(b.rnum0==b.siz) ans.rnum0=b.siz+a.rnum0; ans.rnum1=b.rnum1; if(b.rnum1==b.siz) ans.rnum1=b.siz+a.rnum1; ans.num0=a.num0+b.num0; ans.num1=a.num1+b.num1; ans.maxnum0=Max(a.maxnum0,b.maxnum0); ans.maxnum0=Max(ans.maxnum0,a.rnum0+b.lnum0); ans.maxnum1=Max(a.maxnum1,b.maxnum1); ans.maxnum1=Max(ans.maxnum1,a.rnum1+b.lnum1); return ans; } void _exchange(int idx) { swap(t[idx].lnum0,t[idx].lnum1); swap(t[idx].rnum0,t[idx].rnum1); swap(t[idx].num0,t[idx].num1); swap(t[idx].maxnum0,t[idx].maxnum1); } void push_down(int idx) { if(t[idx].l==t[idx].r)return; if(t[idx].lazy!=-1) { int f=t[idx].lazy; t[idx*2].lazy=t[idx*2+1].lazy=t[idx].lazy; t[idx*2].rev=t[idx*2+1].rev=0; t[idx].lazy=-1; t[idx*2].lnum0=t[idx*2].rnum0=t[idx*2].num0=t[idx*2].maxnum0=(f==0)*t[idx*2].siz; t[idx*2].lnum1=t[idx*2].rnum1=t[idx*2].num1=t[idx*2].maxnum1=(f==1)*t[idx*2].siz; t[idx*2+1].lnum0=t[idx*2+1].rnum0=t[idx*2+1].num0=t[idx*2+1].maxnum0=(f==0)*t[idx*2+1].siz; t[idx*2+1].lnum1=t[idx*2+1].rnum1=t[idx*2+1].num1=t[idx*2+1].maxnum1=(f==1)*t[idx*2+1].siz; } if(t[idx].rev) { t[idx].rev=0; t[idx*2].rev^=1; t[idx*2+1].rev^=1; _exchange(idx*2); _exchange(idx*2+1); } } void _update(int idx) { t[idx].lnum0=t[idx*2].lnum0; if(t[idx*2].lnum0==t[idx*2].siz) t[idx].lnum0=t[idx*2].siz+t[idx*2+1].lnum0; t[idx].lnum1=t[idx*2].lnum1; if(t[idx*2].lnum1==t[idx*2].siz) t[idx].lnum1=t[idx*2].siz+t[idx*2+1].lnum1; t[idx].rnum0=t[idx*2+1].rnum0; if(t[idx*2+1].rnum0==t[idx*2+1].siz) t[idx].rnum0=t[idx*2+1].siz+t[idx*2].rnum0; t[idx].rnum1=t[idx*2+1].rnum1; if(t[idx*2+1].rnum1==t[idx*2+1].siz) t[idx].rnum1=t[idx*2+1].siz+t[idx*2].rnum1; t[idx].num0=t[idx*2].num0+t[idx*2+1].num0; t[idx].num1=t[idx*2].num1+t[idx*2+1].num1; t[idx].maxnum0=Max(t[idx*2].maxnum0,t[idx*2+1].maxnum0); t[idx].maxnum0=Max(t[idx].maxnum0,t[idx*2].rnum0+t[idx*2+1].lnum0); t[idx].maxnum1=Max(t[idx*2].maxnum1,t[idx*2+1].maxnum1); t[idx].maxnum1=Max(t[idx].maxnum1,t[idx*2].rnum1+t[idx*2+1].lnum1); } void _build(int idx,int a,int b) { t[idx].siz=b-a+1; t[idx].l=a;t[idx].r=b; t[idx].lazy=-1; t[idx].rev=0; if(a==b) { if(x[a]) { t[idx].lnum0=t[idx].rnum0=t[idx].num0=t[idx].maxnum0=0; t[idx].lnum1=t[idx].rnum1=t[idx].num1=t[idx].maxnum1=1; } else { t[idx].lnum0=t[idx].rnum0=t[idx].num0=t[idx].maxnum0=1; t[idx].lnum1=t[idx].rnum1=t[idx].num1=t[idx].maxnum1=0; } return; } int m=mid(a,b); _build(idx*2,a,m); _build(idx*2+1,m+1,b); _update(idx); } void _turn(int idx,int a,int b,int f) { push_down(idx); if(t[idx].l==t[idx].r) { t[idx].lnum0=t[idx].rnum0=t[idx].num0=t[idx].maxnum0=(f==0); t[idx].lnum1=t[idx].rnum1=t[idx].num1=t[idx].maxnum1=(f==1); return; } if(a<=t[idx].l&&b>=t[idx].r) { t[idx].lnum0=t[idx].rnum0=t[idx].num0=t[idx].maxnum0=(f==0)*t[idx].siz; t[idx].lnum1=t[idx].rnum1=t[idx].num1=t[idx].maxnum1=(f==1)*t[idx].siz; if(t[idx].rev) t[idx].rev=0; t[idx].lazy=f; return; } int m=mid(t[idx].l,t[idx].r); if(b<=m)_turn(idx*2,a,b,f); else if(a>m)_turn(idx*2+1,a,b,f); else { _turn(idx*2,a,b,f); _turn(idx*2+1,a,b,f); } _update(idx); } void _reverse(int idx,int a,int b) { push_down(idx); if(t[idx].l==t[idx].r) { _exchange(idx); return; } if(a<=t[idx].l&&b>=t[idx].r) { if(t[idx].lazy!=-1) { t[idx].lazy^=1; _exchange(idx); return; } t[idx].rev^=1; _exchange(idx); return; } int m=mid(t[idx].l,t[idx].r); if(b<=m)_reverse(idx*2,a,b); else if(a>m)_reverse(idx*2+1,a,b); else { _reverse(idx*2,a,b); _reverse(idx*2+1,a,b); } _update(idx); } void _count(int idx,int a,int b) { push_down(idx); if(t[idx].l==t[idx].r) { ans+=t[idx].num1; return; } if(a<=t[idx].l&&b>=t[idx].r) { ans+=t[idx].num1; return; } int m=mid(t[idx].l,t[idx].r); if(b<=m)_count(idx*2,a,b); else if(a>m)_count(idx*2+1,a,b); else { _count(idx*2,a,b); _count(idx*2+1,a,b); } } Node _query(int idx,int a,int b) { push_down(idx); if(a==t[idx].l&&b==t[idx].r) { return t[idx]; } int m=mid(t[idx].l,t[idx].r); if(a<=m&&b>m) { return _query(idx*2,a,m)+_query(idx*2+1,m+1,b); } if(a>m) { return _query(idx*2+1,a,b); } if(b<=m) { return _query(idx*2,a,b); } } int main() { scanf("%d%d",&n,&m); for(int i=0;i<n;i++) scanf("%d",&x[i]); _build(1,0,n-1); for(int i=1;i<=m;i++) { int opt,a,b; scanf("%d%d%d",&opt,&a,&b); switch(opt) { case 0: _turn(1,a,b,0);break; case 1: _turn(1,a,b,1);break; case 2: _reverse(1,a,b);break; case 3: ans=0;_count(1,a,b);printf("%d\n",ans);break; case 4: Node res=_query(1,a,b); printf("%d\n",res.maxnum1);break; } } return 0; }
相关文章推荐
- BZOJ 1858 [Scoi2010]序列操作 线段树
- BZOJ 1858: [Scoi2010]序列操作 线段树
- 【bzoj1858】[Scoi2010]序列操作 线段树区间合并
- [省选] [线段树] [BZOJ1858] [SCOI2010] 序列操作
- BZOJ_1858_[Scoi2010]序列操作_线段树
- BZOJ 1858: [Scoi2010]序列操作 [线段树]
- BZOJ 1858 [Scoi2010]序列操作 线段树
- bzoj1858[Scoi2010]序列操作 线段树
- BZOJ 1858 SCOI2010 序列操作 线段树
- 【bzoj 1858】 [Scoi2010]序列操作 线段树
- 线段树 BZOJ1858 [Scoi2010]序列操作
- BZOJ 1858: [Scoi2010]序列操作( 线段树 )
- BZOJ 1858: [Scoi2010]序列操作 线段树
- BZOJ 1858 SCOI2010 序列操作 线段树
- BZOJ 1858: [Scoi2010]序列操作 线段树区间修改查询
- bzoj 1858: [Scoi2010]序列操作【线段树】
- 【BZOJ1858】[Scoi2010]序列操作【线段树】
- BZOJ 1858 [Scoi2010]序列操作 线段树
- 【BZOJ 1858】【SCOI 2010】序列操作【区间线段树】
- BZOJ 1858 [Scoi2010]序列操作 - 线段树