题目链接:https://www.lydsy.com/JudgeOnline/problem.php?id=1858

Description

lxhgww最近收到了一个01序列,序列里面包含了n个数,这些数要么是0,要么是1,现在对于这个序列有五种变换操作和询问操作: 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 对于每一种询问操作,lxhgww都需要给出回答,聪明的程序员们,你们能帮助他吗?

Input

输入数据第一行包括2个数,n和m,分别表示序列的长度和操作数目 第二行包括n个数,表示序列的初始状态 接下来m行,每行3个数,op, a, b,(0 < = op < = 4,0 < = a < = b)

Output

对于每一个询问操作,输出一行,包括1个数,表示其对应的答案

Sample Input

10 10
0 0 0 1 1 0 1 0 1 1
1 0 2
3 0 5
2 2 2
4 0 4
0 3 6
2 3 7
4 2 8
1 0 5
0 5 6
3 3 9

Sample Output

5
2
6
5

HINT

对于30%的数据,1<=n, m<=1000 对于100%的数据,1< = n, m < = 100000

题解:

  考虑怎么对标记进行维护,使用full标记判断该节点所代表的区间是否是同一数字;c标记代表0/1操作,将该节点全部赋值,同时更新full标记

  在翻转标记rev的下推过程中注意偶数次翻转等于没有操作,而赋值操作会清空rev标记。在程序中我们考虑另写一个color函数来将节点染色(全部赋值一个数)

  关键之处在于合并,对于连续的1的个数其实很好维护,细节在于l0,l1,r0,r1即从区间左边到右边和右边到左边有多少个连续的1;值得注意的是合并操作返回的是一颗子树

  那么在统计最大连续的1的时候,我们不能采取累加的方式,而是要在指定区间里合并出一颗新的树,直接输出它的mx1,即最大的连续1的个数

  笔者强调,本题细节较多,请读者耐心阅读并尝试自己打完代码

#include<iostream>
#include<cstdio>
#include<algorithm>
#define N 100005
using namespace std;
int n,m;
int a[N];
struct seg
{
int l,r;
int l0,l1,r0,r1,mx0,mx1,sum0,sum1;
int rev,c,full;
}t[N<<];
void rev(int k)
{
swap(t[k].l0,t[k].l1);
swap(t[k].r0,t[k].r1);
swap(t[k].mx0,t[k].mx1);
swap(t[k].sum0,t[k].sum1);
if(t[k].full!=-)t[k].full^=;
}
void color(int k,int v)
{
t[k].rev=;
int s=t[k].r-t[k].l+;
if(v==)
{
t[k].sum0=t[k].l0=t[k].r0=t[k].mx0=s;
t[k].sum1=t[k].l1=t[k].r1=t[k].mx1=;
}
else
{
t[k].sum0=t[k].l0=t[k].r0=t[k].mx0=;
t[k].sum1=t[k].l1=t[k].r1=t[k].mx1=s;
}
t[k].full=v;
}
seg merge(seg a,seg b)
{
seg tmp;tmp.l=a.l;tmp.r=b.r;
tmp.rev=;tmp.c=-;
tmp.l0=a.l0;tmp.l1=a.l1;
tmp.r0=b.r0;tmp.r1=b.r1;
tmp.mx0=max(a.mx0,b.mx0);
tmp.mx1=max(a.mx1,b.mx1);
tmp.mx0=max(tmp.mx0,a.r0+b.l0);
tmp.mx1=max(tmp.mx1,a.r1+b.l1);
tmp.sum0=a.sum0+b.sum0;
tmp.sum1=a.sum1+b.sum1;
if(a.full==)tmp.l0=a.mx0+b.l0;
else if(a.full==)tmp.l1=a.mx1+b.l1;
if(b.full==)tmp.r0=b.mx0+a.r0;
else if(b.full==)tmp.r1=b.mx1+a.r1;
if(a.full==b.full)
tmp.full=a.full;
else tmp.full=-;
return tmp;
}
void pushup(int k)
{
t[k]=merge(t[k<<],t[k<<|]);
}
void pushdown(int k)
{
if(t[k].l==t[k].r)return;
if(t[k].c!=-)
{
t[k<<].c=t[k<<|].c=t[k].c;
color(k<<,t[k].c);color(k<<|,t[k].c);
t[k].c=-;
}
if(t[k].rev)
{
t[k<<].rev^=;
t[k<<|].rev^=;
rev(k<<);rev(k<<|);
t[k].rev=;
}
}
void build(int k,int l,int r)
{
t[k].l=l;t[k].r=r;
t[k].c=-;
if(l==r)
{
t[k].full=a[l];
if(t[k].full)
{t[k].l1=t[k].r1=t[k].mx1=t[k].sum1=;}
else
{t[k].l0=t[k].r0=t[k].mx0=t[k].sum0=;}
return;
}
int mid=(l+r)>>;
build(k<<,l,mid);build(k<<|,mid+,r);
pushup(k);
}
void change(int k,int x,int y,int v)
{
pushdown(k);
int l=t[k].l,r=t[k].r;
if(l==x&&r==y)
{
color(k,v);
t[k].c=v;
return;
}
int mid=(l+r)>>;
if(mid>=y)change(k<<,x,y,v);
else if(mid<x)change(k<<|,x,y,v);
else
{
change(k<<,x,mid,v);
change(k<<|,mid+,y,v);
}
pushup(k);
}
void rever(int k,int x,int y)
{
pushdown(k);
int l=t[k].l,r=t[k].r;
if(l==x&&r==y)
{
rev(k);
t[k].rev=;
return;
}
int mid=(l+r)>>;
if(mid>=y)rever(k<<,x,y);
else if(mid<x)rever(k<<|,x,y);
else
{
rever(k<<,x,mid);
rever(k<<|,mid+,y);
}
pushup(k);
}
seg ask(int k,int x,int y)
{
pushdown(k);
int l=t[k].l,r=t[k].r;
if(l==x&&y==r)return t[k];
int mid=(l+r)>>;
if(mid>=y)return ask(k<<,x,y);
else if(mid<x)return ask(k<<|,x,y);
else return merge(ask(k<<,x,mid),ask(k<<|,mid+,y));
}
int asksum(int k,int x,int y)
{
pushdown(k);
int l=t[k].l,r=t[k].r;
if(l==x&&y==r)return t[k].sum1;
int mid=(l+r)>>;
if(mid>=y)return asksum(k<<,x,y);
else if(mid<x)return asksum(k<<|,x,y);
else return asksum(k<<,x,mid)+asksum(k<<|,mid+,y);
}
int main()
{
//freopen("a.in","r",stdin);
//freopen("b.out","w",stdout);
scanf("%d%d",&n,&m);
for (int i=;i<=n;i++)
scanf("%d",&a[i]);
build(,,n);
for(int i=;i<=m;i++)
{
int f,x,y;
scanf("%d%d%d",&f,&x,&y);
x++;y++;
switch(f)
{
case :change(,x,y,);break;
case :change(,x,y,);break;
case :rever(,x,y);break;
case :printf("%d\n",asksum(,x,y));break;
case :printf("%d\n",ask(,x,y).mx1);break;
}
}
return ;
}

[BZOJ1858] [SCOI2010] 序列操作 解题报告 (线段树)的更多相关文章

  1. [SCOI2010]序列操作[分块or线段树]

    #include<cstdio> #include<iostream> #define lc k<<1 #define rc k<<1|1 using ...

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

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

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

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

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

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

  5. 洛谷P4247 序列操作 [清华集训] 线段树

    正解:线段树 解题报告: 传送门! 通过这题我get了一个神奇的,叫,线段树五问的东西hhhh 听起来有点中二但感觉真正做题的时候还是比较有用的,,,?感觉会让条理清晰很多呢,所以放一下QwQ →每个 ...

  6. 【序列操作III】线段树

    题目描述 给出序列 a1,a2,…an(0≤ai≤109),有关序列的四种操作: 1. al,al+1,…,ar(1≤l≤r≤n)加上 x(-103≤x≤103) 2. al,al+1,…,ar(1≤ ...

  7. 【序列操作I】线段树

    题目描述 Lxhgww 最近收到了一个 01 序列,序列里面包含了 n(1≤n≤105)个数,这些书要么是 0,要么是 1,现在对这个序列有五种变换操作和询问操作:1. 0 a b ,把[a,b]区间 ...

  8. ACM Minimum Inversion Number 解题报告 -线段树

    C - Minimum Inversion Number Time Limit:1000MS     Memory Limit:32768KB     64bit IO Format:%I64d &a ...

  9. 【分块】bzoj1858 [Scoi2010]序列操作

    分块 Or 线段树 分块的登峰造极之题 每块维护8个值: 包括左端点在内的最长1段: 包括右端点在内的最长1段: 该块内的最长1段: 该块内1的个数: 包括左端点在内的最长0段://这四个是因为可能有 ...

随机推荐

  1. wikioi 1306 机智Trie树

    题目描写叙述 Description 看广播操无聊得非常~你有认为吗?在看广播操一波又一波的人潮涌过再退去.认为非常没意思--于是,偶们的大神犇JHT发明了一个及其好玩的游戏~ 把每一班级的队形看成一 ...

  2. 上传文件 nginx 413错误

    nginx : 413 Request Entity Too Large 上传文件过程发生413 Request Entity Too Large错误,翻译为请求实体过大,断定为nginx限制了请求体 ...

  3. Unity3D——加入剑痕效果(PocketRPG Trail插件)

    首先非常感谢大家的支持,因为近期项目吃紧,所以更新的速度可能会有点慢!希望大家谅解,当然大家的支持是我最大的动力.我也会尽我所能写出更好的文章,当然因为本人是个新手并且工作的内容也不是unity3D. ...

  4. SPOJ 694/705 后缀数组

    思路: 论文题*n Σn-i-ht[i]+1 就是结果 O(n)搞定~ //By SiriusRen #include <cstdio> #include <cstring> ...

  5. Java Swing 托盘闪烁Demo实例

    桌面程序当中,托盘显示是一个常用的功能. C#的WinForm程序要实现托盘是挺轻松的,而Java Swing要实现这个功能虽然也不难, 但是由于Java Swing开发者或许没有C#多,所以看到很多 ...

  6. C# 分隔字符串成为字符串数组的方法(保留分隔符)

    要求如下: source string: mmmmmmynameismickeym separator: m result string []: {"m", "m&quo ...

  7. SpringCloud学习笔记(5)----Spring Cloud Netflix之Eureka的服务认证和集群

    1. Eureka服务认证 1. 引入依赖 <dependency> <groupId>org.springframework.boot</groupId> < ...

  8. ZBrush实用插件ZAppLink简介

    ZAppLink是ZBrush版本推出时被评为最值得期待的插件.事实证明,ZAppLink的出现让工具与工具之间有了交流,搭起软件与软件的沟通桥梁. ZAppLink插件专用于扩展ZBrush®的绘制 ...

  9. C# treeview绑定

    protected void Page_Load(object sender, EventArgs e)        {            if (!IsPostBack)            ...

  10. virtualbox挂载目录失败mount: unknown filesystem type ‘vboxsf’

    转自[https://blog.csdn.net/u011486871/article/details/79443375] [有小修改] 错误提示:Vagrant was unable to moun ...