Codeforces Round 495 (Div. 2) F. Sonya and Bitwise OR(线段树)

原题链接:F. Sonya and Bitwise OR


题目大意:


给出一个长度为 n n n 的数组 a a a,并给出 m m m 次询问以及一个数字 x x x

每个询问形式如下给出:

  • 1 1 1 i i i y y y :将 a i a_{i} ai 位置的值更改为 y y y
  • 2 2 2 l l l r r r :询问在数组区间 [ l , r ] [l, r] [l,r] 内有多少个子区间 [ L , R ] [L,R] [L,R] 满足 l ≤ L ≤ R ≤ r l \leq L \leq R \leq r lLRr ,且 a L o r a L + 1 o r . . . o r a R − 1 o r a R ≥ x a_{L} or \space a_{L+1} or \space ... \space or \space a_{R-1} or \space a_{R} \geq x aLor aL+1or ... or aR1or aRx(其中 o r or or 表示二进制下的 操作)。

解题思路:


乍一看好像没什么很好做的方法,先考虑最暴力的做法是怎么做。

显然,对每个询问,枚举左端点 L L L 暴力向右找右端点 R R R 统计的总复杂度为 O ( m n 2 ) O(mn^{2}) O(mn2)

显然,对右端点的查询,我们做一个二分的优化复杂度可以变成 O ( m n log ⁡ n ) O(mn \log n) O(mnlogn),足够好了,但仍然无法通过。

考虑进一步挖掘一下性质,我们可以发现或操作是单调递增的,即只要某一个位置从 0 0 0 变成 1 1 1 后,则单调保持不变。

进一步思考,因为值域 V ∈ [ 0 , 2 20 ) V \in [0,2^{20}) V[0,220),那么我们的前缀或最多会变化 O ( log ⁡ V ) O(\log V) O(logV) 次,即最多会有 20 20 20 个位置有用(在这次 o r or or 操作时,补上了某个位使 0 0 0 1 1 1)。

我们只需要记录这些存在变化的位置,定下 L L L 之后让 R R R 在这些变化后的位置暴力枚举即可,可知我们最多只会枚举 O ( log ⁡ V ) O(\log V) O(logV) 次。

那问题来了,我们要怎么高效获取某个区间内哪些位置出现变化从而减少复杂度呢?答案很显然,线段树。

线段树内每个节点维护一个 v e c t o r vector vector 保存这个区间内,前/后缀出现变化的位置和其下标。

考虑如何维护区间的 v e c t o r vector vector

  • 假设以及维护好了 [ l , m i d ] , [ m i d + 1 , r ] [l,mid],[mid+1,r] [l,mid],[mid+1,r] 的信息,现在将信息上推至 [ l , r ] [l,r] [l,r]
  • [ l , r ] [l,r] [l,r] 的前缀或信息即 [ l , m i d ] [l,mid] [l,mid] 的前缀或的信息再继续不断或上 [ m i d + 1 , r ] [mid+1,r] [mid+1,r] 的前缀或信息,假设或的过程中发现某个位置的比特位出现变化,则 p u s h b a c k push_back pushback 其位置的值和下标进 v e c t o r vector vector 内,可知枚举的位置总个数不会超过 O ( l o g V ) O(log V) O(logV) 个。
  • [ l , r ] [l,r] [l,r] 的后缀或信息即 [ m i d + 1 , r ] [mid+1,r] [mid+1,r] 的后缀或的信息再继续不断或上 [ l , m i d ] [l,mid] [l,mid] 的后缀或信息,假设或的过程中发现某个位置的比特位出现变化,则 p u s h b a c k push_back pushback 其位置的值和下标进 v e c t o r vector vector 内,可知枚举的位置总个数不会超过 O ( l o g V ) O(log V) O(logV) 个。

考虑答案如何获取,我们采用一个分治的思想:

在这里插入图片描述

  • 假设我们已经计算完了 [ l , m i d ] , [ m i d + 1 , r ] [l,mid],[mid+1,r] [l,mid],[mid+1,r] 的答案,现在将计算横跨 m i d mid mid [ l , r ] [l,r] [l,r] 的答案。
  • 我们已知 [ l , m i d ] [l,mid] [l,mid] 的后缀或数组,以及 [ m i d + 1 , r ] [mid+1,r] [mid+1,r] 的前缀或数组 L L L
  • 我们考虑设置两个双指针 L , R L,R L,R ,一个放在 [ l , m i d ] [l,mid] [l,mid] 的后缀数组 A A A 内,一个放在 [ m i d + 1 , r ] [mid+1,r] [mid+1,r] 的前缀数组 B B B 内,那么显然我们可以枚举 L L L,然后寻找 R R R
  • 查询 [ L , R ] [L,R] [L,R] 的区间或是否 ≥ x \geq x x,即查询是否存在 A [ L ] o r B [ R ] ≥ x A[L] or B[R] \geq x A[L]orB[R]x,满足条件时答案直接加上 r − B [ R ] . s e c o n d + 1 r-B[R].second+1 rB[R].second+1,同时左指针右移( B [ R ] . s e c o n d B[R].second B[R].second 对应原数组内的即下标)。
  • 否则 < x < x <x 时右指针 R R R 向右移动直到满足答案为止。

这样,我们信息上推的复杂度就是 O ( log ⁡ n log ⁡ V ) O(\log n \log V) O(lognlogV) 的,单次查询也是 O ( log ⁡ n log ⁡ V ) O(\log n \log V) O(lognlogV) 的,修改直接照常修改即可,复杂度同时也是 O ( log ⁡ n log ⁡ V ) O(\log n \log V) O(lognlogV) 的。

时间复杂度: O ( m log ⁡ n log ⁡ V ) O(m \log n \log V) O(mlognlogV) ,可以通过,注意一些细节即可。

#include <bits/stdc++.h>
//using namespace std;using PII = std::pair<int, int>;
using i64 = long long;//线段树模板
template<class Info>
struct Segtree {
#define lson k << 1, l, mid
#define rson k << 1 | 1, mid + 1, rint n;std::vector<Info> info;Segtree(int _n) : n(_n), info((_n + 5) << 2) {};Segtree(std::vector<Info>& arr) : Segtree(arr.size() - 1) {std::function<void(int, int, int)> build = [&](int k, int l, int r) {if (l == r) {info[k] = arr[l];return;}int mid = l + r >> 1;build(lson), build(rson);pushup(k, l, r);};build(1, 1, n);}void pushup(int k, int l, int r) {info[k] = merge(info[k << 1], info[k << 1 | 1], l, r);}void Modify(int k, int l, int r, int x, const Info& z) {if (l == r) return void(info[k] = z);int mid = l + r >> 1;if (x <= mid) Modify(lson, x, z);if (x > mid) Modify(rson, x, z);pushup(k, l, r);}Info Query(int k, int l, int r, int x, int y) {if (l >= x && r <= y) return info[k];int mid = l + r >> 1;if (y <= mid) return Query(lson, x, y);if (x > mid) return Query(rson, x, y);return merge(Query(lson, x, y), Query(rson, x, y), std::max(l, x), std::min(y, r));}void Modify(int pos, const Info& z) {Modify(1, 1, n, pos, z);}Info Query(int l, int r) {return Query(1, 1, n, l, r);}
};int X;//注意这里的信息维护和答案上推操作
struct Info {i64 sum;std::vector<PII> L, R;friend Info merge(const Info& a, const Info& b, int QL, int QR) {Info res;res = { a.sum + b.sum, a.L, b.R };//R即 [l,mid] 的后缀或数组,L即[mid+1,r]的前缀或数组auto& R = a.R, & L = b.L;//这里的不同点是从大到小枚举 [mid+1,r] 的后缀或数组,同时查询 [l,mid] 的前缀或数组是否存在合法答案for (int l = R.size() - 1, r = 0; r < L.size(); ++r) {while (l > 0 && (R[l - 1].first | L[r].first) >= X) {--l;}//当答案满足时注意统计信息if ((R[l].first | L[r].first) >= X) {int Rlen = (r + 1 >= L.size() ? QR + 1 : L[r + 1].second) - L[r].second;int Llen = R[l].second - QL + 1;res.sum += 1LL * Rlen * Llen;}}//同时将维护的信息进行上推//保证[l,mid]的前缀或数组不变,枚举[mid+1,r]的前缀或数组上推 [l,r] 的前缀或数组for (auto& [v, p] : b.L) {auto& [x, _] = res.L.back();if ((x | v) > x) {res.L.emplace_back(x | v, p);}}//同时将维护的信息进行上推//保证[mid+1,r]的后缀或数组不变,枚举[l,mid]的后缀或数组上推 [l,r] 的后缀或数组for (auto& [v, p] : a.R) {auto& [x, _] = res.R.back();if ((x | v) > x) {res.R.emplace_back(x | v, p);}}//返回信息return res;}
};void solve() {int n, q;std::cin >> n >> q >> X;std::vector<Info> A(n + 1);for (int i = 1; i <= n; ++i) {int val;std::cin >> val;A[i].L.emplace_back(val, i);A[i].R.emplace_back(val, i);A[i].sum = (val >= X);}Segtree<Info> S(A);for (int i = 1; i <= q; ++i) {int op, l, r;std::cin >> op >> l >> r;if (op == 1) {S.Modify(l, {(r >= X), {{r, l}}, {{r, l}} });} else {std::cout << S.Query(l, r).sum << "\n";}}
}signed main() {std::ios::sync_with_stdio(0);std::cin.tie(0);int t = 1;//std::cin >> t;while (t--) {solve();}return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/402181.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

数据库分库分表的介绍

为什么要分库分表 把存于一个库的数据分散到多个库中&#xff0c;把存于一个表的数据分散到多个表中。如果说读写分离是为了分散数据库读写操作压力&#xff0c;分库分表就是为了分散存储压力&#xff0c;一般情况下&#xff0c;单表数据量到达千万级别&#xff0c;就可以考虑…

基于飞腾平台的Hbase的安装配置

【写在前面】 飞腾开发者平台是基于飞腾自身强大的技术基础和开放能力&#xff0c;聚合行业内优秀资源而打造的。该平台覆盖了操作系统、算法、数据库、安全、平台工具、虚拟化、存储、网络、固件等多个前沿技术领域&#xff0c;包含了应用使能套件、软件仓库、软件支持、软件适…

支持S/MIME证书的邮件客户端有哪些?

S/MIME证书&#xff0c;也叫做邮件安全证书&#xff0c;支持安全/多用途互联网邮件扩展协议&#xff08;S/MIME协议&#xff09;&#xff0c;是通过加密和数字签名来确保电子邮件的安全性、保密性和完整性的数字证书。GDPR、HIPAA、FDA等多个行业都要求邮件发送方在发送邮件时对…

基于R语言遥感随机森林建模与空间预测;遥感数据处理与特征提取;数据分析与可视化

目录 第一章 理论基础与数据准备【夯实基础】 第二章 随机森林建模与预测【讲解实践】 第三章 实践案例与项目 更多应用 随机森林作为一种集成学习方法&#xff0c;在处理复杂数据分析任务中特别是遥感数据分析中表现出色。通过构建大量的决策树并引入随机性&#xff0c;随…

C++ 特殊类设计以及单例模式

目录 1 不能被拷贝 2 只能在堆上创建对象 3 只能在栈上创建对象 4 禁止在堆上创建对象 5 不能被继承的类 6 单例类 特殊类就是一些有特殊需求的类。 1 不能被拷贝 要设计一个防拷贝的类&#xff0c;C98之前我们只需要将拷贝构造以及拷贝赋值设为私有&#xff0c;同时只声明…

RTX 4070 GDDR6显存曝光:性能与成本的平衡之选

近期&#xff0c;关于NVIDIA RTX 4070新显卡的信息曝光&#xff0c;这款显卡将配备较为缓慢的GDDR6显存&#xff0c;而非更高性能的GDDR6X。这一配置的选择引发了业内的广泛关注&#xff0c;特别是在性能与成本的平衡问题上。 新版RTX 4070 OC 2X的核心特点 **1.显存类型与带…

8B 端侧小模型 | 能力全面对标GPT-4V!单图、多图、视频理解端侧三冠王,这个国产AI开源项目火爆全网

这两天&#xff0c; Github上一个 国产开源AI 项目杀疯了&#xff01;一开源就登上了 Github Trending 榜前列&#xff0c;一天就获得将近600 star。 这个项目就是国内大模型四小龙之一面壁智能最新大打造的面壁「小钢炮」 MiniCPM-V 2.6 。它再次刷新端侧多模态天花板&#xf…

微分方程求解的三种解析方法:经典时域法(齐次解+特解,零状态+零输入),冲激响应卷积法、传递函数法

经典时域分析方法 以例题的形式对经典时域解法&#xff08;齐次解特解&#xff09;进行说明&#xff0c;最后进行总结。考虑如下形式微分方程&#xff1a; y ′ ′ ( t ) 5 y ′ ( t ) 6 y ( t ) 2 f ′ ( t ) 6 f ( t ) y\left( t \right) 5y\left( t \right) 6y\left(…

pyinstaller使用

pyinstaller 入门 Pyat5 的安装程序开发PyQt6 的安装程序开发 编写好的程序编译成可执行文件资源文件:用 zip 打包&#xff0c;基本可以压缩到 1/3 大小;然后再用 pyqt 写一个 setup 安装程序&#xff0c;安装到指定目录(安装的过程实际就是把文件解压、拷贝到指定目录、注册到…

[000-01-030].第2节 :Zookeeper本地安装

1.Zookeeper下载地址 1.Zookeeper官网地址 2.会显示Zookeeper的一些版本 2.Zookeeper本地模式安装&#xff1a; 2.1.Zookeeper安装前准备 1.在Centos7虚拟机中安装jdk8 2.2.Zookeeper安装过程&#xff1a; 1.下载zookeeper压缩版本&#xff0c;解压放在opt/moduel目录下…

虚拟人实时主持创意互动方案:赋能峰会论坛会议等活动科技互动感

随着增强现实、虚拟现实等技术的不断发展&#xff0c;“虚拟人实时主持”创意互动模式逐渐代替传统单一真人主持模式&#xff0c;虚拟主持人可以随时随地出现在不同活动现场&#xff0c;也可以同一时间在不同分会场中担任主持工作&#xff0c;在峰会、论坛、会议、晚会、发布会…

计算机网络三级笔记--原创 风远 恒风远博

典型设备中间设备数据单元网络协议物理层中继器、集线器中继器、集线器数据位(bit) binary digit二进 制数据的缩写HUB使用了光纤、 同轴电缆、双绞 线.数据链路层网卡、网桥、交换机网桥、交换机数据帧(Frame)STP、ARQ、 SW、CSMA/CD、 PPP(点对点)、 HDLC、ATM网络层路由器、…

MySQL 管理

启动及关闭 MySQL 服务器 Windows 系统下 启动 MySQL 服务器&#xff1a; 1、通过 “服务” 管理工具&#xff1a; 打开“运行”对话框&#xff08;Win R&#xff09;&#xff0c;输入 services.msc&#xff0c;找到“MySQL”服务&#xff0c;右击选择“启动”。 2、通过命…

汇量科技Mintegral发布全新产品矩阵:助力广告主高效增长与变现

近期&#xff0c;汇量科技旗下程序化互动式广告平台Mintegral正式推出全新产品命名&#xff0c;期望通过简洁明确的产品名称&#xff0c;更好地传达Mintegral的品牌理念&#xff0c;使客户与平台的每一次接触都更加直接高效。 Mintegral AppGrowth(原Mintegral Self-Service Pl…

QLabel设置图像的方法+绘制文本换行显示

1、QLabel设置图像有两种方法 (1) void setPicture(const QPicture &); (2) void setPixmap(const QPixmap &); QPicture和QPixmap都是继承于QPaintDevice&#xff0c;它们都可以通过加载图片的方式获取&#xff1a;bool load(QIODevice *dev, const char *format …

【直播预告】智能机器人赛道技术培训定档8.20

在不远的将来&#xff0c;机器人可能会成为我们日常生活中不可或缺的伙伴&#xff0c;它们在工业生产线上精准操作&#xff0c;在家庭中提供温馨陪伴&#xff0c;甚至在探索未知领域中担当先锋。而现在&#xff0c;正是我们拥抱这一未来&#xff0c;深入了解并掌握智能机器人技…

【Python机器学习】树回归——树剪枝

如果一棵树节点过多&#xff0c;表明该模型可能对数据进行了过拟合。 通过降低决策树的复杂度来避免过拟合的过程称为剪枝。提过提前终止条件&#xff0c;实际上就是在进行一种所谓的预剪枝&#xff1b;另一种形式的剪枝需要使用测试集和训练集&#xff0c;称作后剪枝。 预剪…

PMP到底有什么用?

PMP 就是项目管理证书&#xff0c;全称是项目管理专业人士资格认证&#xff0c;对于一个在项目管理岗位混迹五年的老油条来说&#xff0c;PMP 证书是敲开项目管理岗位的第一块砖&#xff0c;每年考 PMP 的人都很多&#xff0c;要是 PMP 证书没有价值&#xff0c;还会有那么多人…

c语言-经典例题

C语言-经典例题 一、单项选择题 1、 -- A 2、 -- C y<5 --是关系运算符的优先级大于&& -- 是逻辑运算符 3、 -- B - D选项&#xff1a;c是float类型&#xff0c;所以c/2是1.5 4、 -- C 从后往前执行&#xff08;先算后面的&a…

利用住宅代理应对机器人流量挑战:识别、使用与检验指南

引言 什么是机器人流量&#xff1f;其工作原理是什么&#xff1f; 机器人流量来自哪里&#xff1f; 合法使用机器人时如何避免被拦截&#xff1f; 如何检验恶意机器人流量&#xff1f; 总结 引言 你是否曾经遇到过访问某个网站时&#xff0c;被要求输入验证码或完成一些其…