分块 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. [bzoj 2844]线性基+高斯消元

    题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=2844 又用到线性基+高斯消元的套路题了,因为经过高斯消元以后的线性基有非常好的序关系,所以 ...

  2. Linux下rsync 安装与配置

    1.什么是rsync Rsync(remote synchronize)是一个远程数据同步工具,可通过LAN/WAN快速同步多台主机间的文件.Rsync使用所谓的“Rsync算法”来使本地和远 程两个 ...

  3. Spring学习--通过注解配置 Bean (一)

    在 classpath 中扫描组件: 组件扫描(component scanning): Spring 能够从 classpath 下自动扫描 , 侦测和实例化具有特定注解的组件. 特定组件包括: @ ...

  4. struts学习笔记(四)

    一. 文件的上传: 1). 表单需要注意的 3 点 2). Struts2 的文件上传实际上使用的是 Commons FileUpload 组件, 所以需要导入 commons-fileupload- ...

  5. 【BZOJ4031】【HEOI2015】小Z的房间 [Matrix-Tree][行列式]

    小Z的房间 Time Limit: 10 Sec  Memory Limit: 256 MB[Submit][Status][Discuss] Description 你突然有了一个大房子,房子里面有 ...

  6. Python小程序之用户登陆接口

    编写登陆接口 输入用户名密码 认证成功后显示欢迎信息 输错三次后锁定 程序逻辑图: 代码: #!/usr/bin/env python #_*_ coding:UTF-8 _*_ #__author_ ...

  7. 常见的makefile写法【转】

    转自:http://blog.csdn.net/ghostyu/article/details/7755177 版权声明:本文为博主原创文章,未经博主允许不得转载. .目标名称,摆脱手动设置目标名称 ...

  8. python 学习笔记 多进程

    要让python程序实现多进程,我们先了解操作系统的相关知识 Unix/Linux操作系统提供了一个fork()系统调用,他非常特殊,普通的函数调用,调用一次,返回一次,但是fork调用一次, 返回两 ...

  9. 【 HAProxy 】学习笔记

    一.haproxy的功能: HAProxy vs LVS        HAProxy支持tcp和http两种代理模式,而lvs仅支持tcp代理模式        HAProxy相比LVS的使用要简单 ...

  10. hdu 1224(动态规划 DAG上的最长路)

    Free DIY Tour Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Tot ...