【BZOJ 1858】【SCOI 2010】序列操作

2023-10-07 15:58
文章标签 操作 序列 bzoj 2010 scoi 1858

本文主要是介绍【BZOJ 1858】【SCOI 2010】序列操作,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

0~3操作都是很裸的线段树操作,主要是这个4操作有点复杂。
定义一下数组的含义:
l0/1:从左端点开始连续的0/1的个数
r0/1:从右端点开始连续的0/1的个数
m0/1:连续的最长的0/1串
sum:1的个数
在update操作的时候,l和r数组的更新都可以直接由孩子得到,但要注意一类情况:比如左孩子全部是1,那么就可以把右孩子左端的1连起来。m数组由两种情况得到,一种是孩子的m数组,还有一种是左孩子的右端和右孩子的左端拼在一起得到。

0~2操作都只要打上lazy-tag标记即可,注意的是如果打上了tag0/1标记,其他两个标记要被清除掉。
3操作只要查询sum即可。
对于4操作,我一开始想的就是直接统计,后来发现很难处理区间合并的情况。后来网上找了一种写法,就是把有贡献的区间一层一层合并存在一个新的节点里面,这样只要update一下就可以得到m数组了,非常神奇的写法。

#include<cmath>
#include<cstdio>
#include<vector>
#include<queue>
#include<cstring>
#include<iomanip>
#include<stdlib.h>
#include<iostream>
#include<algorithm>
#define inf 1000000000
#define mod 1000000007
#define N 400005
#define fo(i,a,b) for(i=a;i<=b;i++)
#define fd(i,a,b) for(i=a;i>=b;i--)
using namespace std;
int lson[N],rson[N],l0[N],l1[N],r0[N],r1[N],len[N],m0[N],m1[N],sum[N];
int ll[N],rr[N],tag0[N],tag1[N],tagrev[N],a[N];
int tot,total,n,m,i,root,opt,l,r;
void update(int x)
{int ls = lson[x] , rs = rson[x];l0[x] = l0[ls]; l1[x] = l1[ls];r0[x] = r0[rs]; r1[x] = r1[rs];if (l0[ls] == len[ls]) l0[x] = l0[ls] + l0[rs];if (l1[ls] == len[ls]) l1[x] = l1[ls] + l1[rs];if (r0[rs] == len[rs]) r0[x] = r0[ls] + r0[rs];if (r1[rs] == len[rs]) r1[x] = r1[ls] + r1[rs];m0[x] = max(r0[ls]+l0[rs],max(m0[ls],m0[rs]));m1[x] = max(r1[ls]+l1[rs],max(m1[ls],m1[rs]));sum[x] = sum[ls] + sum[rs];
}void build(int &rt,int l,int r)
{rt = ++tot;ll[rt] = l; rr[rt] = r; len[rt] = r - l + 1;tag0[rt] = tag1[rt] = tagrev[rt] = 0;if (l == r){lson[rt] = rson[rt] = 0;l1[rt] = r1[rt] = m1[rt] = sum[rt] = (a[l] == 1);l0[rt] = r0[rt] = m0[rt] = (a[l] == 0);return;}int mid = (l + r) >> 1;build(lson[rt],l,mid); build(rson[rt],mid+1,r);update(rt);
}
void mark0(int x)
{tag0[x] = 1; tag1[x] = tagrev[x] = 0;l0[x] = r0[x] = m0[x] = len[x];l1[x] = r1[x] = m1[x] = sum[x] = 0;
}
void mark1(int x)
{tag1[x] = 1; tag0[x] = tagrev[x] = 0;l0[x] = r0[x] = m0[x] = 0;l1[x] = r1[x] = m1[x] = sum[x] = len[x];
}
void markrev(int x)
{tagrev[x] ^= 1;swap(l0[x],l1[x]); swap(r0[x],r1[x]);swap(m0[x],m1[x]); sum[x] = len[x] - sum[x];
}
void pushdown(int x)
{if (tag0[x]) {mark0(lson[x]); mark0(rson[x]); tag0[x] = 0;}if (tag1[x]) {mark1(lson[x]); mark1(rson[x]); tag1[x] = 0;}if (tagrev[x]) {markrev(lson[x]); markrev(rson[x]); tagrev[x] = 0;}}
void change(int rt,int l,int r,int opt)
{if (ll[rt] > r || rr[rt] < l) return;pushdown(rt);if (l <= ll[rt] && rr[rt] <= r){if (opt == 0) mark0(rt); if (opt == 1) mark1(rt);if (opt == 2) markrev(rt); return;}change(lson[rt],l,r,opt); change(rson[rt],l,r,opt);update(rt);
}
int query1(int rt,int l,int r)
{if (ll[rt] > r || rr[rt] < l) return 0;pushdown(rt);if (l <= ll[rt] && rr[rt] <= r) return sum[rt];return query1(lson[rt],l,r) + query1(rson[rt],l,r);
}
int query2(int rt,int l,int r)
{pushdown(rt);if (l == ll[rt] && r == rr[rt]) return rt;int mid = (ll[rt] + rr[rt]) >> 1;if (r <= mid) return query2(lson[rt],l,r);if (l > mid) return query2(rson[rt],l,r);int ans = ++total;lson[ans] = query2(lson[rt],l,mid); rson[ans] = query2(rson[rt],mid+1,r);update(ans);return ans;
}
int main()
{scanf("%d%d",&n,&m);fo(i,1,n) scanf("%d",&a[i]);build(root,1,n);fo(i,1,m){scanf("%d%d%d",&opt,&l,&r); l++; r++;if (opt <= 2) {change(root,l,r,opt); continue;}if (opt == 3) {printf("%d\n",query1(root,l,r)); continue;}if (opt == 4) {total = tot; printf("%d\n",m1[query2(root,l,r)]); continue;}}return 0;
}

这篇关于【BZOJ 1858】【SCOI 2010】序列操作的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/158831

相关文章

Java使用Curator进行ZooKeeper操作的详细教程

《Java使用Curator进行ZooKeeper操作的详细教程》ApacheCurator是一个基于ZooKeeper的Java客户端库,它极大地简化了使用ZooKeeper的开发工作,在分布式系统... 目录1、简述2、核心功能2.1 CuratorFramework2.2 Recipes3、示例实践3

Java利用JSONPath操作JSON数据的技术指南

《Java利用JSONPath操作JSON数据的技术指南》JSONPath是一种强大的工具,用于查询和操作JSON数据,类似于SQL的语法,它为处理复杂的JSON数据结构提供了简单且高效... 目录1、简述2、什么是 jsONPath?3、Java 示例3.1 基本查询3.2 过滤查询3.3 递归搜索3.4

Python使用DrissionPage中ChromiumPage进行自动化网页操作

《Python使用DrissionPage中ChromiumPage进行自动化网页操作》DrissionPage作为一款轻量级且功能强大的浏览器自动化库,为开发者提供了丰富的功能支持,本文将使用Dri... 目录前言一、ChromiumPage基础操作1.初始化Drission 和 ChromiumPage

利用Go语言开发文件操作工具轻松处理所有文件

《利用Go语言开发文件操作工具轻松处理所有文件》在后端开发中,文件操作是一个非常常见但又容易出错的场景,本文小编要向大家介绍一个强大的Go语言文件操作工具库,它能帮你轻松处理各种文件操作场景... 目录为什么需要这个工具?核心功能详解1. 文件/目录存javascript在性检查2. 批量创建目录3. 文件

Redis中管道操作pipeline的实现

《Redis中管道操作pipeline的实现》RedisPipeline是一种优化客户端与服务器通信的技术,通过批量发送和接收命令减少网络往返次数,提高命令执行效率,本文就来介绍一下Redis中管道操... 目录什么是pipeline场景一:我要向Redis新增大批量的数据分批处理事务( MULTI/EXE

C++从序列容器中删除元素的四种方法

《C++从序列容器中删除元素的四种方法》删除元素的方法在序列容器和关联容器之间是非常不同的,在序列容器中,vector和string是最常用的,但这里也会介绍deque和list以供全面了解,尽管在一... 目录一、简介二、移除给定位置的元素三、移除与某个值相等的元素3.1、序列容器vector、deque

使用Python高效获取网络数据的操作指南

《使用Python高效获取网络数据的操作指南》网络爬虫是一种自动化程序,用于访问和提取网站上的数据,Python是进行网络爬虫开发的理想语言,拥有丰富的库和工具,使得编写和维护爬虫变得简单高效,本文将... 目录网络爬虫的基本概念常用库介绍安装库Requests和BeautifulSoup爬虫开发发送请求解

Oracle存储过程里操作BLOB的字节数据的办法

《Oracle存储过程里操作BLOB的字节数据的办法》该篇文章介绍了如何在Oracle存储过程中操作BLOB的字节数据,作者研究了如何获取BLOB的字节长度、如何使用DBMS_LOB包进行BLOB操作... 目录一、缘由二、办法2.1 基本操作2.2 DBMS_LOB包2.3 字节级操作与RAW数据类型2.

JDK多版本共存并自由切换的操作指南(本文为JDK8和JDK17)

《JDK多版本共存并自由切换的操作指南(本文为JDK8和JDK17)》本文介绍了如何在Windows系统上配置多版本JDK(以JDK8和JDK17为例),并通过图文结合的方式给大家讲解了详细步骤,具有... 目录第一步 下载安装JDK第二步 配置环境变量第三步 切换JDK版本并验证可能遇到的问题前提:公司常

使用Folium在Python中进行地图可视化的操作指南

《使用Folium在Python中进行地图可视化的操作指南》在数据分析和可视化领域,地图可视化是一项非常重要的技能,它能够帮助我们更直观地理解和展示地理空间数据,Folium是一个基于Python的地... 目录引言一、Folium简介与安装1. Folium简介2. 安装Folium二、基础使用1. 创建