bzoj 1858 序列操作
来源:互联网 发布:中联软件靠谱吗 编辑:程序博客网 时间:2024/06/06 20:17
有毒的线段树
一个01序列,支持以下操作
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
先不考虑操作3
线段树的节点要维护
从左端点开始连续的1的个数
从右端点开始连续的1的个数
当前区间最长的连续的1的长度
当前区间1的个数
当前区间是否都是1
合并的时候不妨设左右区间分别为
如果
否则
弱化的题目大概这样就可以了
然后取反的怎么做呢?
是不是同时维护一下对于0的这五个值,取反的时候直接交换就可以了
同时我们发现当前区间都是1等价于0的个数为0,所以维护四个值就好
另外值得注意的是这里线段树支持的两个操作(取反,覆盖)是不独立的
也就是取反的时候不能直接覆盖lazy,而要由原来的lazy计算新的lazy
具体见代码
#include<cstdio>#include<cstring>#include<algorithm>#include<iostream>using namespace std;const int INF = 0x3f3f3f3f;const int maxn = 112345;struct Info{ int v[2][4]; // lma max rma sum void maintain(int val){ if(val<=1){ int all = v[0][3]+v[1][3]; for(int i=0;i<4;i++) v[1^val][i] = 0,v[val][i] = all; } else{ for(int i=0;i<4;i++) swap(v[0][i],v[1][i]); } } void clear(){ memset(v,0,sizeof(v)); } void init(){ memset(v,0,sizeof(v)); for(int i=0;i<4;i++) v[0][i] = 1; } void out(){ puts("----------------------st"); for(int i=0;i<=1;i++){ printf("%d : (ls %d ma %d rs %d) sum = %d\n",i,v[i][0],v[i][1],v[i][2],v[i][3]); } puts("-----------------------here"); }};Info operator + (const Info & L,const Info & R){ Info ret; ret.clear(); for(int i=0;i<=1;i++){ ret.v[i][3] = L.v[i][3] + R.v[i][3]; ret.v[i][0] = L.v[i][0]; if(L.v[i^1][3]==0) ret.v[i][0] += R.v[i][0]; ret.v[i][2] = R.v[i][2]; if(R.v[i^1][3]==0) ret.v[i][2] += L.v[i][2]; ret.v[i][1] = max(L.v[i][1],R.v[i][1]); ret.v[i][1] = max(ret.v[i][1],L.v[i][2]+R.v[i][0]); } return ret;}#define lson o<<1,l,m#define rson o<<1|1,m+1,r#define root 1,1,n#define Now int o,int l,int r#define Mid int m=l + (r-l)/2Info val[maxn*4];int lazy[maxn*4];int chag(int x){ if(x==-1) return 2; if(x<2) return x^1; return -1;}void push_down(Now){ int v = lazy[o]; lazy[o] = -1; if(l==r) return; val[o<<1].maintain(v); val[o<<1|1].maintain(v); if(v<=1){ lazy[o<<1] = lazy[o<<1|1] = v; } else{ lazy[o<<1] = chag(lazy[o<<1]); lazy[o<<1|1] = chag(lazy[o<<1|1]); }}void update(Now,int ul,int ur,int v){ if(ul <= l && r <= ur){ if(v<=1) lazy[o] = v; else lazy[o] = chag(lazy[o]); val[o].maintain(v); return; } Mid; if(lazy[o]!=-1) push_down(o,l,r); if(ul <= m){ update(lson,ul,ur,v); } if(m+1<=ur){ update(rson,ul,ur,v); } val[o] = val[o<<1] + val[o<<1|1];}Info query(Now,int ql,int qr){ if(ql <= l && r <= qr){ return val[o]; } Info ret; ret.clear(); if(lazy[o]!=-1){ push_down(o,l,r); } Mid; if(ql <= m)ret = query(lson,ql,qr) + ret; if(m+1<=qr)ret = ret + query(rson,ql,qr); return ret;}void buildtree(Now){ if(l!=r){ Mid; buildtree(lson); buildtree(rson); val[o] = val[o<<1] + val[o<<1|1]; } else val[o].init();}int main(){ int n,m; while(~scanf("%d %d",&n,&m)){ int v; memset(lazy,-1,sizeof(lazy)); buildtree(root); for(int i=1;i<=n;i++){ scanf("%d",&v); update(root,i,i,v); } int l,r; while(m--){ scanf("%d %d %d",&v,&l,&r); l++,r++; if(v<=2) update(root,l,r,v); else{ if(v == 3) printf("%d\n",query(root,l,r).v[1][3]); else printf("%d\n",query(root,l,r).v[1][1]); } } } return 0;}
0 0
- bzoj 1858 序列操作
- 【BZOJ 1858】 [Scoi2010]序列操作
- BZOJ 1858 [Scoi2010]序列操作
- bzoj 1858: [Scoi2010]序列操作
- BZOJ 1858 [Scoi2010]序列操作
- bzoj 1858: [Scoi2010] 序列操作 题解
- BZOJ 1858 SCOI2010 序列操作 线段树
- BZOJ 1858 SCOI 2010 序列操作
- bzoj 1858 序列操作(线段树)
- bzoj 1858 序列操作 线段树
- BZOJ 1858 [Scoi2010]序列操作 线段树
- 【bzoj 1858】 [Scoi2010]序列操作 线段树
- bzoj 1858: [Scoi2010]序列操作 线段树
- BZOJ 1858 [Scoi2010]序列操作 线段树
- 【BZOJ 1858】【SCOI 2010】序列操作
- BZOJ 1858 [Scoi2010]序列操作 线段树
- BZOJ 1858 序列操作 [线段树]
- BZOJ 1858: [Scoi2010]序列操作 线段树
- hibernate学习(1)
- 10_您已经学习了 DTD,下一步呢?
- AndroidManifest.xml文件解析
- hive-建表、数据抽取及了解表信息
- 2016 UESTC Training for Dynamic Programming J - 柱爷抢银行II dp单调队列优化
- bzoj 1858 序列操作
- Python里的OS模块常用函数说明
- 博客已搬家
- <常量数组的应用> UVA 10082 WERTYU
- rbf神经网络的实现
- CodeForces 608D Zuma(DP)
- linux一些热键和man page
- Linux command:apt-get
- Vector