分块 Or 线段树 分块的登峰造极之题

每块维护8个值:

包括左端点在内的最长1段;

包括右端点在内的最长1段;

该块内的最长1段;

该块内1的个数;

包括左端点在内的最长0段;//这四个是因为可能有翻转操作,需要swap 0有关的标记 和 1有关的标记

包括右端点在内的最长0段;

该块内的最长0段;

该块内0的个数。

2个懒标记:是否翻转,覆盖成了什么。

怎么处理一个块上有两个标记的情况呢?

若该块原来没有任何标记,或要打的标记和原本的标记种类相同,则直接打上标记;

若已有翻转标记,再覆盖时则先清除翻转标记,再打上覆盖标记;

若已有覆盖标记,再翻转时,则直接将覆盖标记取反。

So 某个块上同时只会有1个标记。

代码能力题,同样无法体现分块相对于线段树的“代码简介优势”,不推荐写。耗时也多于线段树。

P.S.注意取最长段的时候的细节……如下代码中高亮部分。

P.S.P.S.注意Pushdown的时机。

 #include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
int len[],lenl[],lenr[],n,m,l[],r[],num[],sum,sz,x,y;
bool a[];
int len0[],lenl0[],lenr0[],sum1[],sum0[];
int delta[],op;
bool Spin[];
int Res,Num;char C,CH[];
inline int G()
{
Res=;C='*';
while(C<''||C>'')C=getchar();
while(C>=''&&C<=''){Res=Res*+(C-'');C=getchar();}
return Res;
}
inline void P(long long x)
{
Num=;if(!x){putchar('');puts("");return;}
while(x>)CH[++Num]=x%,x/=;
while(Num)putchar(CH[Num--]+);
puts("");
}
void Pushdown(const int &p)
{
if(delta[p]!=-)
{
for(int i=l[p];i<=r[p];i++) a[i]=delta[p];
delta[p]=-;
}
else if(Spin[p])
{
for(int i=l[p];i<=r[p];i++) a[i]^=;
Spin[p]=false;
}
}
inline void Work(const int &Lb,const int &Rb,const int &sym)
{
if(sym==||sym==) {for(int i=Lb;i<=Rb;i++) a[i]=sym;}
else if(sym==) {for(int i=Lb;i<=Rb;i++) a[i]^=;}
int cnt=;
for(int i=l[num[Lb]];i<=r[num[Lb]];i++) {if(a[i]) break; cnt++;}//暴力lenl0
lenl0[num[Lb]]=cnt; cnt=;
for(int i=r[num[Lb]];i>=l[num[Lb]];i--) {if(a[i]) break; cnt++;}//暴力lenr0
lenr0[num[Lb]]=cnt; cnt=;
int Longest=;
for(int i=l[num[Lb]];i<=r[num[Lb]];i++)//暴力len0
{
if(a[i]) cnt=; else cnt++;
if(cnt>Longest) Longest=cnt;
}
len0[num[Lb]]=Longest; cnt=;
for(int i=l[num[Lb]];i<=r[num[Lb]];i++) {if(!a[i]) break; cnt++;}//暴力lenl
lenl[num[Lb]]=cnt; cnt=;
for(int i=r[num[Lb]];i>=l[num[Lb]];i--) {if(!a[i]) break; cnt++;}//暴力lenr
lenr[num[Lb]]=cnt; cnt=; Longest=;
for(int i=l[num[Lb]];i<=r[num[Lb]];i++)//暴力len
{
if(!a[i]) cnt=; else cnt++;
if(cnt>Longest) Longest=cnt;
}
len[num[Lb]]=Longest; cnt=;
for(int i=l[num[Lb]];i<=r[num[Lb]];i++) if(a[i]) cnt++;//暴力sum1
sum1[num[Lb]]=cnt; cnt=;
for(int i=l[num[Lb]];i<=r[num[Lb]];i++) if(!a[i]) cnt++;//暴力sum0
sum0[num[Lb]]=cnt;
}
void makeblock()
{
memset(delta,-,sizeof(delta));
sz=sqrt((double)n*0.5);
for(sum=;sum*sz<n;sum++)
{
l[sum]=(sum-)*sz+;
r[sum]=sum*sz;
for(int i=l[sum];i<=r[sum];i++) num[i]=sum;
Work(l[sum],r[sum],-);
}
l[sum]=sz*(sum-)+; r[sum]=n;
for(int i=l[sum];i<=r[sum];i++) num[i]=sum;
Work(l[sum],r[sum],-);
}
inline void Update(const int &L,const int &R,const bool &sym)
{
Pushdown(num[L]);
Pushdown(num[R]);
if(num[L]==num[R]) Work(L,R,sym);
else
{
Work(L,r[num[L]],sym);
Work(l[num[R]],R,sym);
for(int i=num[L]+;i<num[R];i++)
{
if(Spin[i]) Spin[i]=false; delta[i]=sym;
len[i]=lenl[i]=lenr[i]=sum1[i]=sym ? r[i]-l[i]+ : ;
len0[i]=lenl0[i]=lenr0[i]=sum0[i]=sym ? : r[i]-l[i]+;
}
}
}
inline void Update_Spin(const int &L,const int &R)
{
Pushdown(num[L]);
Pushdown(num[R]);
if(num[L]==num[R]) Work(L,R,);
else
{
Work(L,r[num[L]],);
Work(l[num[R]],R,);
for(int i=num[L]+;i<num[R];i++)
{
if(delta[i]==-) Spin[i]^=; else delta[i]^=;
swap(sum1[i],sum0[i]);
swap(len[i],len0[i]);
swap(lenl[i],lenl0[i]);
swap(lenr[i],lenr0[i]);
}
}
}
inline void Query_Sum(const int &L,const int &R)
{
int ans=;
Pushdown(num[L]);
Pushdown(num[R]);
if(num[L]==num[R]) {for(int i=L;i<=R;i++) if(a[i]) ans++;}
else
{
for(int i=L;i<=r[num[L]];i++) if(a[i]) ans++;
for(int i=l[num[R]];i<=R;i++) if(a[i]) ans++;
for(int i=num[L]+;i<num[R];i++) ans+=sum1[i];
}
P(ans);
}
135 inline void Query_Len(const int &L,const int &R)
136 {
137 Pushdown(num[L]);
138 Pushdown(num[R]);
139 int ans=0,cnt=0;
140 if(num[L]==num[R])
141 {
142 for(int i=L;i<=R;i++)
143 {
144 if(a[i]) cnt++; else cnt=0;
145 ans=max(ans,cnt);
146 }
147 P(ans);
148 }
149 else
150 {
151 int kua=0,cntr=0;
152 for(int i=r[num[L]];i>=L;i--) {if(!a[i]) break; kua++;}
153 for(int i=l[num[R]];i<=R;i++) {if(!a[i]) break; cntr++;}
154 for(int i=num[L]+1;i<num[R];i++)
155 {
156 if(kua) kua+=lenl[i];
157 ans=max(ans,kua);
158 if(len[i]!=r[i]-l[i]+1) kua=0;
159 if(!kua&&lenr[i]) kua=lenr[i];
160 ans=max(ans,len[i]);
161 }
162 for(int i=L;i<=r[num[L]];i++)
163 {
164 if(a[i]) cnt++; else cnt=0;
165 ans=max(ans,cnt);
166 } cnt=0;
167 for(int i=l[num[R]];i<=R;i++)
168 {
169 if(a[i]) cnt++; else cnt=0;
170 ans=max(ans,cnt);
171 }
172 P(max(ans,kua+cntr));
173 }
174 }
int main()
{
n=G();m=G();
for(int i=;i<=n;i++) a[i]=G();
makeblock();
for(int i=;i<=m;i++)
{
op=G();x=G();y=G();x++;y++;
if(op==) Update(x,y,);
else if(op==) Update(x,y,);
else if(op==) Update_Spin(x,y);
else if(op==) Query_Sum(x,y);
else Query_Len(x,y);
}
return ;
}

【分块】bzoj1858 [Scoi2010]序列操作的更多相关文章

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

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

  2. BZOJ1858 [Scoi2010]序列操作(线段树)

    题目链接 [Scoi2010]序列操作 考验代码能力的一道好题. 思想还是很简单的(直接上线段树),但是比较难写. #include <bits/stdc++.h> using names ...

  3. BZOJ1858[Scoi2010]序列操作 题解

    题目大意: 有一个01序列,现在对于这个序列有五种变换操作和询问操作: 0 a b 把[a, b]区间内的所有数全变成0:1 a b 把[a, b]区间内的所有数全变成1:2 a b 把[a,b]区间 ...

  4. [BZOJ1858] [SCOI2010] 序列操作 解题报告 (线段树)

    题目链接:https://www.lydsy.com/JudgeOnline/problem.php?id=1858 Description lxhgww最近收到了一个01序列,序列里面包含了n个数, ...

  5. bzoj1858: [Scoi2010]序列操作

    lazy-tag线段树. #include<cstdio> #include<algorithm> #include<cstring> using namespac ...

  6. bzoj千题计划177:bzoj1858: [Scoi2010]序列操作

    http://www.lydsy.com/JudgeOnline/problem.php?id=1858 2018 自己写的第1题,一遍过 ^_^ 元旦快乐 #include<cstdio> ...

  7. [待码][BZOJ1858]SCOI2010序列操作 jzyzoj1655

    待码的线段树.....太长了看上去不是很想写 [ 什么破理由啊摔,不要脸 ] 嗯先水几道再写

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

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=1858 线段树...调了一个上午...(后面带 // 的都是改出来的) lazy 标记的下放好 ...

  9. 【BZOJ-1858】序列操作 线段树

    1858: [Scoi2010]序列操作 Time Limit: 10 Sec  Memory Limit: 64 MBSubmit: 1961  Solved: 991[Submit][Status ...

随机推荐

  1. git使用笔记(八)团队协作

    By francis_hao    Nov 24,2016       本文由 刘英皓 创作,采用 知识共享 署名-非商业性使用-相同方式共享 3.0 中国大陆 许可协议进行许可.欢迎转载,请注明出处 ...

  2. Fragmenttabhost的使用教程

    1.准备tab的图标,放到mipmap目录下面,大小64x64,准备2种,一种是选中的,一种是未选中的,如下图 2.重写fragmentabhost,防止调用fragment每次点击tab都要重新调用 ...

  3. 线段树模板 CDOJ1057

    UESTCOJ不知道为什么进不去了哇 跟着叉姐的算法讲堂写的板子 叉姐的思路真的好清晰啊,一定是练习的多并且理解的够深了 希望自己也可以每天进步一点点吧 代码: #include <map> ...

  4. nodejs npm insttall 带不带-g这个参数的区别

    -g 中的g是global的意思所以带-g这个参数是全局安装,不带-g这个参数是本地安装. 在windows系统中全局安装的目录在:C:\Users\linsenq\AppData\Roaming\n ...

  5. oracle的sql语句训练

    --查询工资最高的人的名字select ename ,sal from emp where sal=(select max(sal) from emp );--求出员工的工资在所有人的平均工资之上的人 ...

  6. Install the Active Directory Administration Tools on Windows Server

    安装 Active Directory 管理工具 To manage your directory from an EC2 Windows instance, you need to install ...

  7. bzoj3127/3697 [Usaco2013 Open]Yin and Yang

    传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=3127 http://www.lydsy.com/JudgeOnline/problem.ph ...

  8. DotNet 学习笔记 应用状态管理

    Application State Options --------------------------------------------------------------------- *Htt ...

  9. [bzoj1568][JSOI2008]Blue Mary开公司——李超线段树

    题目大意 题解 这道题需要用到一种叫做李超线段树的东西.我对于李超线段树,是这样理解的: 给节点打下的标记不进行下传,而是仅仅在需要的时候进行下传,这就是所谓永久化标记. 对于这道题,借用一张图, 这 ...

  10. LeetCode Regular Expression Matching 网上一个不错的实现(非递归)

    '.' Matches any single character.'*' Matches zero or more of the preceding element. The matching sho ...