bzoj 1858: [Scoi2010]序列操作 || 洛谷 P2572
记一下:线段树占空间是$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的更多相关文章
- (WAWAWAWAWAWA) BZOJ 1858: [Scoi2010]序列操作
二次联通门 : BZOJ 1858: [Scoi2010]序列操作 /* BZOJ 1858: [Scoi2010]序列操作 已经... 没有什么好怕的的了... 16K的代码... 调个MMP啊.. ...
- bzoj 1858: [Scoi2010]序列操作
1858: [Scoi2010]序列操作 Time Limit: 10 Sec Memory Limit: 64 MB 线段树,对于每个区间需要分别维护左右和中间的1和0连续个数,并在op=4时特殊 ...
- BZOJ 1858: [Scoi2010]序列操作( 线段树 )
略恶心的线段树...不过只要弄清楚了AC应该不难.... ---------------------------------------------------------------- #inclu ...
- bzoj 1858: [Scoi2010]序列操作【线段树】
合并中间那块的时候没取max--WAWAWA 在线段树上维护一堆东西,分别是len区间长度,sm区间内1的个数,ll0区间从左开始最长连续0,ml0区间中间最长连续0,rl0区间从右开始最长连续0,l ...
- 1858: [Scoi2010]序列操作
1858: [Scoi2010]序列操作 Time Limit: 10 Sec Memory Limit: 64 MB Submit: 3397 Solved: 1624 [Submit][Statu ...
- bzoj1858[Scoi2010]序列操作 线段树
1858: [Scoi2010]序列操作 Time Limit: 10 Sec Memory Limit: 64 MBSubmit: 3079 Solved: 1475[Submit][Statu ...
- 【题解】Luogu P2572 [SCOI2010]序列操作
原题传送门:P2572 [SCOI2010]序列操作 这题好弱智啊 裸的珂朵莉树 前置芝士:珂朵莉树 窝博客里对珂朵莉树的介绍 没什么好说的自己看看吧 操作1:把区间内所有数推平成0,珂朵莉树基本操作 ...
- P2572 [SCOI2010]序列操作
对自己 & \(RNG\) : 骄兵必败 \(lpl\)加油! P2572 [SCOI2010]序列操作 题目描述 lxhgww最近收到了一个01序列,序列里面包含了n个数,这些数要么是0,要 ...
- BZOJ_1858_[Scoi2010]序列操作_线段树
BZOJ_1858_[Scoi2010]序列操作_线段树 Description lxhgww最近收到了一个01序列,序列里面包含了n个数,这些数要么是0,要么是1,现在对于这个序列有五种变换操作和询 ...
随机推荐
- sdk manager 创建的虚拟机启动的时候总是在Android字样解决
一直显示Android字样.仅仅须要删除文件夹下的snapshots.img 找到sdk的文件夹下的\tools\lib\emulator,然后删除上面的文件snapshots.img就可以,我的sd ...
- Leetcode--easy系列10
#205 Isomorphic Strings Given two strings s and t, determine if they are isomorphic. Two strings are ...
- 编程基础知识——Java JNI开发流程(2)
android中使用jni调用本地C++库 android平台上的本地库文件后缀 .so.类似windows上的dll文件. 要在android上使用jni.首先须要下载android ndk. 操作 ...
- 成员函数指针 C++ FAQ LITE — Frequently Asked Questions
http://www.sunistudio.com/cppfaq/pointers-to-members.html C++ FAQ LITE — Frequently Asked Questions ...
- SQL - 创建一个学生表,要求有主键约束和非空约束
CREATE TABLE [dbo].[Student] ( [ID] [int] NOT NULL, [Name] [nchar](10) NOT NULL, [Age] [int] NOT NUL ...
- Linux-github 搭建静态博客
1.在Github上创建一个新的Repository 到你的github上 https://github.com去create a new repository命名为 github.myblog 2. ...
- C# LINQ Unity 单例
C# LINQ 1. 自定义 Master,Kongfu 类 1 class Master 2 { 3 4 public int Id { get; set; } 5 public string ...
- 怎样用Google APIs和Google的应用系统进行集成(8)----怎样把Google Blogger(博客)的JSON Schema转换成XML的Schema(XSD)?
在Google RESTFul API中,Google Blogger API(Google博客API)应该和我们的生活离得近期:由于差点儿非常多人每天都在看博客,都在写博客,都听说过博客.在前面的G ...
- Android NDK编程浅入深出之--Android.mk
Android.mk Android.mk是一个向Android NDK构建系统描写叙述NDK项目的GUN Makefile片段.它是每个NDK项目的必备组件. 构建系统希望它出如今jni子文 ...
- iOS开发——高级篇——多线程dispatch_apply
我们知道遍历数组是一个相对耗时的操作,而同时手机的核是越来越多,所以我们需要充分利用iOS多核的作用. 特别是在遍历操作中还有其他耗时操作.像我们平时直接遍历数组的操作 ,i< ,i++){ / ...