记一下:线段树占空间是$2^{ceil(log2(n))+1}$

这个就是一个线段树区间操作题,各种标记的设置、转移都很明确,只要熟悉这类题应该说是没有什么难度的。

由于对某区间set之后该区间原先待进行的取反操作失效(被覆盖),因此规定tag同时存在时set的标记先进行操作,这样对区间加上set标记时要去掉原有的取反标记。

对于操作4,线段树上每个区间维护6个值,分别表示:该区间最多的连续0/1,从左侧数起/从右侧数起/其中任意位置。题目中不问连续0,为什么连续0也要维护呢?这是为了在进行取反操作时,O(1)完成标记的维护(直接交换对0、1维护的3个值就行了)。

对于操作3,线段树上每个区间维护该区间1的个数。此时不需要额外记录0的个数,0的个数可以由区间总数-1的个数得到。

规定:set的标记为-1时表示不需要set操作,为0/1时表示需要set为该标记的值。

注意一点:对于取反的tag,每次取反操作的时候都是将tag取反,而不是置为1,不然在同一个位置取反两次就不对了。

各个标记含义同普通线段树:当前节点已经操作,其所有(任意级的)子节点待操作。维护的时候转移都是递推,细的就不讲了,有点多,要细心比对。

然而...

感觉自己药丸啊...调了三个小时才调出来,各种各样诡异的错误...如果省选考这个肯定没法做了..

幸好这个样例够强。。有一些奇怪的错误通过样例就查出来了,过了样例就1A了,不然真的不知道要调到什么时候。。。

note:以下程序中打了注释的语句都是错过的。。。

 #include<cstdio>
#include<cstring>
#include<algorithm>
#define mid ((l+r)>>1)
#define lc (num<<1)
#define rc (num<<1|1)
using namespace std;
struct Th
{
int a,b,c;
bool d;//是否全部是1
int len;
Th(int aa=,int bb=,int cc=,bool dd=,int ll=):a(aa),b(bb),c(cc),d(dd),len(ll){}
};
int num1[],maxnum[][][],settag[];
bool revtag[];
int n,m;
//定义tag同时存在时settag先进行操作
int a[];
int L,R,x;
//maxnum[][0/1][0/1/2]表示最多的连续0/1,接左侧/接右侧/中间
void pd(int l,int r,int num)
{
if(settag[num]!=-)
{
num1[lc]=settag[num]*(mid-l+);
maxnum[lc][][]=maxnum[lc][][]=maxnum[lc][][]=(-settag[num])*(mid-l+);
maxnum[lc][][]=maxnum[lc][][]=maxnum[lc][][]=settag[num]*(mid-l+);
num1[rc]=settag[num]*(r-mid);
maxnum[rc][][]=maxnum[rc][][]=maxnum[rc][][]=(-settag[num])*(r-mid);
maxnum[rc][][]=maxnum[rc][][]=maxnum[rc][][]=settag[num]*(r-mid);
revtag[lc]=revtag[rc]=;
settag[lc]=settag[rc]=settag[num];
settag[num]=-;
}
if(revtag[num])
{
num1[lc]=mid-l+-num1[lc];
num1[rc]=r-mid-num1[rc];
swap(maxnum[lc][][],maxnum[lc][][]);
swap(maxnum[lc][][],maxnum[lc][][]);
swap(maxnum[lc][][],maxnum[lc][][]);
swap(maxnum[rc][][],maxnum[rc][][]);
swap(maxnum[rc][][],maxnum[rc][][]);
swap(maxnum[rc][][],maxnum[rc][][]);
revtag[lc]^=;revtag[rc]^=;
revtag[num]=;
}
}
void update(int l,int r,int num)
{
num1[num]=num1[lc]+num1[rc];
maxnum[num][][]=maxnum[lc][][];
if(num1[lc]==) maxnum[num][][]=(mid-l+)+maxnum[rc][][];
maxnum[num][][]=maxnum[rc][][];
if(num1[rc]==) maxnum[num][][]=(r-mid)+maxnum[lc][][];
maxnum[num][][]=maxnum[lc][][];
if(num1[lc]==mid-l+) maxnum[num][][]=(mid-l+)+maxnum[rc][][];
maxnum[num][][]=maxnum[rc][][];
if(num1[rc]==r-mid) maxnum[num][][]=(r-mid)+maxnum[lc][][];
maxnum[num][][]=max(max(maxnum[lc][][],maxnum[rc][][]),maxnum[lc][][]+maxnum[rc][][]);
maxnum[num][][]=max(max(maxnum[lc][][],maxnum[rc][][]),maxnum[lc][][]+maxnum[rc][][]);
}
void build(int l,int r,int num)
{
if(l==r)
{
num1[num]=(a[l]==);
maxnum[num][][]=maxnum[num][][]=maxnum[num][][]=(a[l]==);
maxnum[num][][]=maxnum[num][][]=maxnum[num][][]=(a[l]==);
settag[num]=-;
return;
}
build(l,mid,lc);
build(mid+,r,rc);
settag[num]=-;update(l,r,num);
}
void setto(int l,int r,int num)
{
if(L<=l&&r<=R)
{
revtag[num]=;settag[num]=x;
num1[num]=x*(r-l+);//mid-l+1
maxnum[num][][]=maxnum[num][][]=maxnum[num][][]=(-x)*(r-l+);//mid-l+1
maxnum[num][][]=maxnum[num][][]=maxnum[num][][]=x*(r-l+);//mid-l+1
return;
}
pd(l,r,num);
if(L<=mid) setto(l,mid,lc);
if(mid<R) setto(mid+,r,rc);
update(l,r,num);
}
void revx(int l,int r,int num)
{
if(L<=l&&r<=R)
{
revtag[num]^=;
num1[num]=r-l+-num1[num];
swap(maxnum[num][][],maxnum[num][][]);
swap(maxnum[num][][],maxnum[num][][]);
swap(maxnum[num][][],maxnum[num][][]);
return;
}
pd(l,r,num);
if(L<=mid) revx(l,mid,lc);
if(mid<R) revx(mid+,r,rc);
update(l,r,num);
}
int query1(int l,int r,int num)
{
if(L<=l&&r<=R) return num1[num];
pd(l,r,num);
int ans=;
if(L<=mid) ans+=query1(l,mid,lc);
if(mid<R) ans+=query1(mid+,r,rc);
return ans;
}
Th query2(int l,int r,int num)
{
//if(L<=l&&r<=R) return Th(maxnum[num][1][0],maxnum[num][1][1],maxnum[num][1][2],num1[num]==r-l+1,1);
if(L<=l&&r<=R) return Th(maxnum[num][][],maxnum[num][][],maxnum[num][][],num1[num]==r-l+,r-l+);//num1[num]==1
pd(l,r,num);
Th ans,t1,t2;
if(L<=mid) t1=query2(l,mid,lc);
if(mid<R) t2=query2(mid+,r,rc);
ans.a=t1.a;
//if(t1.d||t1.len==0) ans.a=t1.len+t2.a;
if(t1.d) ans.a=t1.len+t2.a;
ans.b=t2.b;
//if(t2.d||t2.len==0) ans.b=t2.len+t1.b;
if(t2.d) ans.b=t2.len+t1.b;
ans.c=max(max(t1.c,t2.c),t1.b+t2.a);
ans.d=t1.d&&t2.d;
ans.len=t1.len+t2.len;
return ans;
}
int main()
{
int i,idx;Th ttt;
scanf("%d%d",&n,&m);
for(i=;i<=n;i++) scanf("%d",&a[i]);
build(,n,);
for(i=;i<=m;i++)
{
scanf("%d%d%d",&idx,&L,&R);L++,R++;
if(idx==) x=,setto(,n,);
else if(idx==) x=,setto(,n,);
else if(idx==) revx(,n,);
else if(idx==) printf("%d\n",query1(,n,));
else if(idx==) {ttt=query2(,n,);printf("%d\n",max(max(ttt.a,ttt.b),ttt.c));}
}
return ;
}

bzoj 1858: [Scoi2010]序列操作 || 洛谷 P2572的更多相关文章

  1. (WAWAWAWAWAWA) BZOJ 1858: [Scoi2010]序列操作

    二次联通门 : BZOJ 1858: [Scoi2010]序列操作 /* BZOJ 1858: [Scoi2010]序列操作 已经... 没有什么好怕的的了... 16K的代码... 调个MMP啊.. ...

  2. bzoj 1858: [Scoi2010]序列操作

    1858: [Scoi2010]序列操作 Time Limit: 10 Sec  Memory Limit: 64 MB 线段树,对于每个区间需要分别维护左右和中间的1和0连续个数,并在op=4时特殊 ...

  3. BZOJ 1858: [Scoi2010]序列操作( 线段树 )

    略恶心的线段树...不过只要弄清楚了AC应该不难.... ---------------------------------------------------------------- #inclu ...

  4. bzoj 1858: [Scoi2010]序列操作【线段树】

    合并中间那块的时候没取max--WAWAWA 在线段树上维护一堆东西,分别是len区间长度,sm区间内1的个数,ll0区间从左开始最长连续0,ml0区间中间最长连续0,rl0区间从右开始最长连续0,l ...

  5. 1858: [Scoi2010]序列操作

    1858: [Scoi2010]序列操作 Time Limit: 10 Sec Memory Limit: 64 MB Submit: 3397 Solved: 1624 [Submit][Statu ...

  6. bzoj1858[Scoi2010]序列操作 线段树

    1858: [Scoi2010]序列操作 Time Limit: 10 Sec  Memory Limit: 64 MBSubmit: 3079  Solved: 1475[Submit][Statu ...

  7. 【题解】Luogu P2572 [SCOI2010]序列操作

    原题传送门:P2572 [SCOI2010]序列操作 这题好弱智啊 裸的珂朵莉树 前置芝士:珂朵莉树 窝博客里对珂朵莉树的介绍 没什么好说的自己看看吧 操作1:把区间内所有数推平成0,珂朵莉树基本操作 ...

  8. P2572 [SCOI2010]序列操作

    对自己 & \(RNG\) : 骄兵必败 \(lpl\)加油! P2572 [SCOI2010]序列操作 题目描述 lxhgww最近收到了一个01序列,序列里面包含了n个数,这些数要么是0,要 ...

  9. BZOJ_1858_[Scoi2010]序列操作_线段树

    BZOJ_1858_[Scoi2010]序列操作_线段树 Description lxhgww最近收到了一个01序列,序列里面包含了n个数,这些数要么是0,要么是1,现在对于这个序列有五种变换操作和询 ...

随机推荐

  1. 【网络】TCP的拥塞控制

    一.拥塞控制的一般原理 拥塞:对网络中某一资源的需求超过了该资源所能提供的可用部分 拥塞控制是防止过多的数据注入到网络,这样可以使网络中的路由器或链路不致过载,拥塞控制是一个全局性的过程. 流量控制往 ...

  2. JAVA数组去除重复数据

    一.用List集合实现   , , , , , , ,}; List<Integer> list = new ArrayList<Integer>(); ; i<str. ...

  3. 容器使用笔记(List篇)

    上一篇博客介绍了Dictionary,这篇博客介绍List的相关内容. C#中要存储一组数据.我们会想到数组Array,ArrayList,List这三个对象,当中,数组是最早出现的,我们就从数组開始 ...

  4. 【Mongodb教程 第十一课 】MongoDB 聚合

    聚合操作过程中的数据记录和计算结果返回.聚合操作分组值从多个文档,并可以执行各种操作,分组数据返回单个结果.在SQL COUNT(*)和group by 相当于MongoDB的聚集. aggregat ...

  5. Eclipse导入项目: No projects are found to import

    Eclipse导入项目: No projects are found to import  如果发导入工程import的时候,出现”No projects are found to import” 的 ...

  6. 2 TypeScript--Hello World

    安装好TypeScript后,我们来完成第一个页面--Hello World 新建index.html文件: <!DOCTYPE html> <html> <head&g ...

  7. SVN代码丢失惊魂

    吓死了吓死了!要是那些代码丢了的话,要重新码一遍,我宁愿去吃屎. 某天快下班走人的时候,从SVN服务器update了本地代码,结果发现代码变回了上个月的样子.看SVN的日志,发现提交记录从6月22日一 ...

  8. busybox相关的工具

    1 mdev busybox里面的类似于udev的工具,学名micro udev. mdev -s扫描/sys目录,如果是设备的话,就会为之在/dev目录下创建设备结点. 2 busybox执行不同的 ...

  9. struts2的一些小问题

    1.action和ValueStack的关系2.ValueStack的类set()方法和setValue()方法的区别3.ValueStack的类push()方法的作用4.从ValueStack对象中 ...

  10. 构造json参数时key的引号和js string转json的三种方式

    {name:"dd",age:"16"} {"name":"dd","age":"16&q ...