题意简述

维护一个序列,支持如下操作

  • 把[a, b]区间内的所有数全变成0
  • 把[a, b]区间内的所有数全变成1
  • 把[a,b]区间内所有的0变成1,所有的1变成0
  • 询问[a, b]区间内总共有多少个1
  • 询问[a, b]区间内最多有多少个连续的1

题解思路

线段树

对于每个节点,维护对应区间

  • sum:1的个数
  • L0:连续0的最大长度
  • L1:连续1的最长长度
  • l0:包含区间左端点的连续0的最大长度
  • l1:包含区间左端点的连续1的最大长度
  • r0:包含区间右端点的连续0的最大长度
  • r1:包含区间右端点的连续1的最大长度
  • la:-1表示不变,0表示全为0,1表示全为1
  • tn:0表示不变,1表示翻转

可推出关系

ls表示左儿子,rs表示右儿子,lenl表示左儿子区间长度,lenr表示右儿子区间长度

\(L0 = max(L0_{ls}, L0_{rs}, r0_{ls}+l0_{rs})\)

\(l0 = l0_{ls} + l0_{rs} * (l0_{ls} == lenl)\)

\(r0 = r0_{rs} + r0_{ls} * (r0_{rs} == lenr)\)

L1,l1,r1同理可得。

下传标记时先判断la,因为全都变为1个数可以覆盖翻转的结果

代码

#include <cstdio>
#include <algorithm>
#define ci const int
#define ls x<<1
#define rs x<<1|1
#define mid ((l+r)>>1)
using std::max; using std::swap;
int n,m,opt,a,b,t;
struct Node1 { int sum,L0,L1,l0,l1,r0,r1,la,tn; };
struct Node2 { int sum,L1,l1,r1; };
struct Segement_Tree {
Node1 s[400010];
void push_up(ci& x,ci& lenl,ci& lenr) {
s[x].sum=s[ls].sum+s[rs].sum;
s[x].L0=max(max(s[ls].L0,s[rs].L0),s[ls].r0+s[rs].l0);
s[x].L1=max(max(s[ls].L1,s[rs].L1),s[ls].r1+s[rs].l1);
s[x].l0=s[ls].l0+s[rs].l0*(s[ls].l0==lenl);
s[x].l1=s[ls].l1+s[rs].l1*(s[ls].l1==lenl);
s[x].r0=s[rs].r0+s[ls].r0*(s[rs].r0==lenr);
s[x].r1=s[rs].r1+s[ls].r1*(s[rs].r1==lenr);
}
void push_down(ci& x,ci& lenl,ci& lenr) {
if (s[x].la^-1) {
s[ls].sum=s[ls].L1=s[ls].l1=s[ls].r1=s[x].la*lenl;
s[rs].sum=s[rs].L1=s[rs].l1=s[rs].r1=s[x].la*lenr;
s[ls].L0=s[ls].l0=s[ls].r0=(s[x].la^1)*lenl;
s[rs].L0=s[rs].l0=s[rs].r0=(s[x].la^1)*lenr;
s[ls].la=s[rs].la=s[x].la; s[x].la = -1; s[ls].tn=s[rs].tn=0;
}
if (s[x].tn) {
s[ls].sum=lenl-s[ls].sum; s[rs].sum=lenr-s[rs].sum;
swap(s[ls].L0,s[ls].L1); swap(s[rs].L0,s[rs].L1);
swap(s[ls].l0,s[ls].l1); swap(s[rs].l0,s[rs].l1);
swap(s[ls].r0,s[ls].r1); swap(s[rs].r0,s[rs].r1);
s[ls].tn^=1; s[rs].tn^=1; s[x].la=-1; s[x].tn=0;
}
}
void build(ci& x,ci& l,ci& r) {
s[x].la=-1;
if (l==r) { scanf("%d",&t); s[x]=(Node1){t,t^1,t,t^1,t,t^1,t,-1,0}; return; }
build(ls,l,mid); build(rs,mid+1,r);
push_up(x,mid-l+1,r-mid);
}
void change(ci& x,ci& L,ci& R,ci& l,ci& r,ci& k) {
if (L<=l&&r<=R) {
int x1=k*(r-l+1),x2=(k^1)*(r-l+1);
s[x] = (Node1){x1,x2,x1,x2,x1,x2,x1,k,0};
return;
}
if (R<l||r<L) return;
push_down(x,mid-l+1,r-mid);
change(ls,L,R,l,mid,k); change(rs,L,R,mid+1,r,k);
push_up(x,mid-l+1,r-mid);
}
void turn(ci& x,ci& L,ci& R,ci& l,ci& r) {
if (L<=l&&r<=R) {
s[x].sum=r-l+1-s[x].sum; s[x].tn^=1;
swap(s[x].L0,s[x].L1); swap(s[x].l0,s[x].l1); swap(s[x].r0,s[x].r1);
return;
}
if (R<l||r<L) return;
push_down(x,mid-l+1,r-mid);
turn(ls,L,R,l,mid); turn(rs,L,R,mid+1,r);
push_up(x,mid-l+1,r-mid);
}
Node2 query(ci& x,ci& L,ci& R,ci& l,ci& r) {
if (L<=l&&r<=R) return (Node2){s[x].sum,s[x].L1,s[x].l1,s[x].r1};
if (R<l||r<L) return (Node2){0,0,0,0};
push_down(x,mid-l+1,r-mid);
Node2 s,s1=query(ls,L,R,l,mid),s2=query(rs,L,R,mid+1,r);
s.sum=s1.sum+s2.sum;
s.L1=max(max(s1.L1,s2.L1),s1.r1+s2.l1);
s.l1=s1.l1+s2.l1*(s1.l1==mid-l+1);
s.r1=s2.r1+s1.r1*(s2.r1==r-mid);
return s;
}
}sgt;
int main() {
scanf("%d%d",&n,&m);
sgt.build(1,1,n);
for (register int i=1; i<=m; ++i) {
scanf("%d%d%d",&opt,&a,&b); ++a; ++b;
if (opt==4) printf("%d\n",sgt.query(1,a,b,1,n).L1);
else if (opt==3) printf("%d\n",sgt.query(1,a,b,1,n).sum);
else if (opt==2) sgt.turn(1,a,b,1,n);
else sgt.change(1,a,b,1,n,opt);
}
}

洛谷 P2572 [SCOI2010]序列操作的更多相关文章

  1. 洛谷$P2572\ [SCOI2010]$ 序列操作 线段树/珂朵莉树

    正解:线段树/珂朵莉树 解题报告: 传送门$w$ 本来是想写线段树的,,,然后神仙$tt$跟我港可以用珂朵莉所以决定顺便学下珂朵莉趴$QwQ$ 还是先写线段树做法$QwQ$? 操作一二三四都很$eas ...

  2. 洛谷P2572 [SCOI2010]序列操作

    线段树 pushdown写的很浪~ #include<cstdio> #include<cstdlib> #include<algorithm> #include& ...

  3. 洛谷P2572 [SCOI2010]序列操作(ODT)

    题解 题意 题目链接 Sol ODT板子题..... // luogu-judger-enable-o2 #include<bits/stdc++.h> #define LL long l ...

  4. 洛谷P2572 [SCOI2010]序列操作(珂朵莉树)

    传送门 珂朵莉树是个吼东西啊 这题线段树代码4k起步……珂朵莉树只要2k…… 虽然因为这题数据不随机所以珂朵莉树的复杂度实际上是错的…… 然而能过就行对不对…… (不过要是到时候noip我还真不敢打… ...

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

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

  6. P2572 [SCOI2010]序列操作

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

  7. Luogu P2572 [SCOI2010]序列操作 线段树。。

    咕咕了...于是借鉴了小粉兔的做法ORZ... 其实就是维护最大子段和的线段树,但上面又多了一些操作....QWQ 维护8个信息:1/0的个数(sum),左/右边起1/0的最长长度(ls,rs),整段 ...

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

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

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

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

随机推荐

  1. Discuz ML! V3.X 代码注入漏洞

    Discuz ML! V3.X 代码注入漏洞 前言 Discuz!ML是一个由CodersClub.org创建的多语言,集成,功能齐全的开源网络平台,用于构建像"社交网络"这样的互 ...

  2. mysql重启遇到的问题

    不知道是不是每次更新 MySQL 软件之后都需要执行数据库升级指令?在我进行过的几次软件升级之后,总会在 MySQL 的日志中见到 “[ERROR] Missing system table mysq ...

  3. STM32F072从零配置工程-实现delay功能

    因为是使用SysTick来作为延时时钟,因此在这里给出SysTick时钟的寄存器: CTRL:SysTick控制及状态寄存器 位段 名称 类型 复位值 描述 16 COUNTFLAG R/W 0 如果 ...

  4. CSDN怎么一键转载别人的博客

    在参考"如何快速转载CSDN中的博客"后,由于自己不懂html以及markdown相关知识,所以花了一些时间来弄明白怎么转载博客,以下为转载CSDN博客步骤和一些知识小笔记. 参考 ...

  5. YuniKorn 介绍

    一.YuniKorn 简介 YuniKorn 是一种轻量级的通用资源调度程序,适用于容器编排系统.它的创建是为了一方面在大规模,多租户环境中有效地实现各种工作负载的细粒度资源共享,另一方面可以动态地创 ...

  6. Excel催化剂图表系列之一整套IBCS图表大放送,一秒变图表专家

    不知不觉,从2019年1月初开始打算来一波图表系列的功能,首选IBCS标准化图表,结果入坑后,一路跌至谷底,和预想的完全不是一个量级的工作量,为了追求一键式.通用化及细节的严谨性,过程中好几次文件报错 ...

  7. C#3.0新增功能02 匿名类型

    连载目录    [已更新最新开发文章,点击查看详细] 匿名类型提供了一种方便的方法,可用来将一组只读属性封装到单个对象中,而无需首先显式定义一个类型. 类型名由编译器生成,并且不能在源代码级使用. 每 ...

  8. PHP强制转换类型

    PHP强制转换类型   获取数据类型 : 1.如果想查看某个表达式的值和类型,用var_dump(). 2.如果只是想得到一个易读懂的类型的表达方式用于调试,用 gettype().3.要查看某个类型 ...

  9. python面向对象-封装-property-接口-抽象-鸭子类型-03

    封装 什么是封装: # 将复杂的丑陋的隐私的细节隐藏到内部,对外提供简单的使用接口 或 # 对外隐藏内部实现细节,并提供访问的接口 为什么需要封装 1.为了保证关键数据的安全性 2.对外部隐藏内部的实 ...

  10. 一文彻底搞懂Java中的环境变量

    一文搞懂Java环境变量 记得刚接触Java,第一件事就是配环境变量,作为一个初学者,只知道环境变量怎样配,在加上各种IDE使我们能方便的开发,而忽略了其本质的东西,只知其然不知其所以然,随着不断的深 ...