【树状数组】codeforce 1288 E. Messenger Simulator

news/2025/9/21 15:44:18/文章来源:https://www.cnblogs.com/RomanLin/p/19087028

View Post

【树状数组】codeforce 1288 E. Messenger Simulator

题目

https://codeforces.com/problemset/problem/1288/E

题解

用以下测试用例进行讲解:

4 2
3 2

上述测试用例的执行过程如图所示:
未命名绘图

初始状态下,第 \(i\) 个人位于第 \(i\) 层,想维护的目标是每个人到达过的最高层 \(mx[i]\) 和最低层 \(mi[i]\),显然初始时 \(mx[i] = mi[i] = i\)

收到消息的人会上升到第一层,因此最低层只需要判断这个人有没有收到过消息或者初始时就位于第一层即可,原本在收到消息的人之上的人各自所处的楼层都会下降一层,即从第 \(x\) 层变到第 \(x + 1\) 层。

当收到第 \(3\) 个人的消息的时候,第 \(2\) 个人从原本位于第二层变为位于第三层,第 \(1\) 个人从原本位于第一层变为位于第二层,而收到消息的人,也就是第 \(3\) 个人会变为位于第一层。

随后,收到第 \(2\) 个人的消息的时候,第 \(1\) 个人从原本位于第二层变为位于第三层,第 \(3\) 个人从原本位于第一层变为位于第二层,而收到消息的人,也就是第 \(2\) 个人会变为第一层。

对于这个过程,我们容易联想到插入排序的过程是类似的,时间复杂度为 \(O(n)\) ~ \(O(n^2)\)。但是极端情况下,每次收到消息的人都是最底层的人收到消息,此时会造成数组大量的移动操作,时间复杂度为:\(O(n^2)\),是不可接受的。有此分析,我们可以得到的启发是想解决该问题就需要避免数组大量的移动操作

在数组不进行任何移动操作时,要做的就是将消息发送者所处楼层上面所有人的所处楼层都增加 \(1\),然后将消息发送者直接加在楼层最上层,并且删除消息发送者原本在数组中所处位置对答案的影响,问题就转化为了以下两个子问题:

  1. 如何快速为消息发送者所处楼层上面所有人的所处楼层增加 \(1\)
  2. 如何剔除收到消息的人在原来位置上对答案的影响?

为解决子问题 1,可以使用树状数组。维护三个长度为 \(n + m\) 的数组 \(a, b, tr\),分别代表人的编号,所处楼层和树状数组,初始化时将 \(n\) ~ \(1\) 依次填入 \(a[1]\) ~ \(a[n]\)\(b[1]\) ~ \(b[n]\),其余位置初始化为 \(0\) 即可,树状数组初始化时全部填 \(0\)。随后的 \(m\) 个数依次填入 \(a[n + 1]\) ~ \(a[n + m]\),当填入 \(a[i](i \geq n + 1)\) 时,不妨记上一次出现值为 \(a[i]\) 的位置为 \(j\),则需要使用树状数组将 \(j + 1\) ~ \(i\) 的每个位置都增加 \(1\),具体的操作可以将 \(j + 1\) ~ \(n\) 的每个位置增加 \(1\),将 \(i + 1\) 的每个位置减少 \(1\)

为解决子问题 2,只需要将 \(a[j]\) 置为负无穷大即可。

不妨记 \(x\) 为使用树状数组计算出第 \(i\) 个位置增加了多少个 \(1\),那么,\(b[i] + x\) 就是 \(a[i]\) 所处的楼层。当解决子问题 2 之前,需要先计算一次 \(a[j]\) 所处楼层。在所有操作都完成以后,需要再遍历一遍数组(遍历第 \(n + 1\) ~ \(n + m\) 个位置即可),计算出每个人所处过的楼层的最高层。至于每个人所处过楼层的最低层,只需要当收到那个人消息时,将其最低层更新为 \(1\) 即可,其它情况所处楼层大小只会单调不减。

参考代码

#include<bits/stdc++.h>
using namespace std;
using ll = long long;constexpr int N = 3e5 + 7;
constexpr int INF = -1e9;
int n, m, w, len;
int tr[N << 1];
int a[N << 1];
int b[N << 1];
int idx[N];
int mi[N];
int mx[N];int lowbit(int x) {return x & -x;
}void add(int idx, int val) {while (idx <= len) {tr[idx] += val;idx += lowbit(idx);}
}int sum(int idx) {int res = 0LL;while (idx > 0) {res += tr[idx];idx -= lowbit(idx);}return res;
}int main() {ios::sync_with_stdio(false);cin.tie(nullptr);cout.tie(nullptr);cin >> n >> m;len = n + m;for (int i = 1; i <= n; ++ i) a[i] = b[i] = n - i + 1, mi[i] = mx[i] = i, idx[n - i + 1] = i;for (int i = n + 1; i <= n + m; ++ i) {cin >> b[i];w = b[i];mi[w] = 1;mx[w] = max(mx[w], sum(idx[w]) + a[idx[w]]);a[idx[w]] = INF;add(idx[w] + 1, 1);add(i + 1, -1);idx[w] = i;}for (int i = 1; i <= len; ++ i) if (a[i] >= 0) mx[b[i]] = max(mx[b[i]], a[i] + sum(i));for (int i = 1; i <= n; ++ i) cout << mi[i] << ' ' << mx[i] << '\n';return 0;
}

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

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

相关文章

exsi 6.7 打补丁

exsi 6.7 打补丁exsi 6.7 打补丁esxi 6.7 打补丁WARNING:All commands run on the ESXi shell are logged and may be included insupport bundles. Do not provide passwords directly on the command line.Most tool…

Ubuntu 24.04 安装 DaVinci Resolve

Ubuntu 24.04 安装 DaVinci Resolve Step1: 下载并安装 chmod +x DaVinci_Resolve_Studio_19.0_Linux.run sudo ./DaVinci_Resolve_Studio_19.0_Linux.run -i可能会遇到依赖的问题, 需要先安装以下的几个库, 再以跳过检…

Promise中处理请求超时问题

1. 使用 Promise.race() 处理超时Promise<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <script src="https://code.jquery.com/jquery-3.6.0.min.js">&l…

图解26:老生常谈的OSI网络模型

哈哈,之前画的不能在老的图了,重新拿出来让AI加个码看看效果,没有一点失真还不错,

【C++】指针

内存 程序中最重要的一件事,就是内存。当启动一个程序的时候,所有的代码都被载入到内存当中,内存中的所有的二进制指令都在告诉计算机你的代码需要做什么。 没有内存,计算机什么都做不了,而指针对于管理和操纵内存…

Quart

Quart📌 在软件/编程里 Quart 是一个 Python 异步 Web 框架,API 和 Flask 几乎完全兼容,但基于 asyncio,所以可以用 async/await 写异步代码。你可以把它理解为 “异步版 Flask”。典型用途:写高并发 Web 服务、…

AI驱动建筑行业数字化转型

AI驱动建筑行业数字化转型精细化管理为目标的数字化转型是建筑产业发展的必然趋势 建筑业当前面临着行业增速下降、劳动力成本上升、单个项目投标家数增加、资源环境约束加剧等挑战,且随着时代发展,建筑项目的规…

详细介绍:前端学习——CSS

详细介绍:前端学习——CSSpre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", …

VSCode 把代码发送到激活状态下的终端

VSCode 把代码发送到激活状态下的终端 你有没有遇到过这样的情况:在VSCode里写Python代码时,经常需要打开好几个终端。但问题是,Shift+Enter快捷键只能把选中的代码发送到第一个终端。有时候,如果VSCode意外重启,…

java设计模式-工厂模式(文件上传) - 实践

java设计模式-工厂模式(文件上传) - 实践2025-09-21 15:33 tlnshuju 阅读(0) 评论(0) 收藏 举报pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block…

线性结构之数组[基于郝斌课程]

线性结构:把所有的结点用一根线穿起来 连续存储[数组]什么叫做数组:元素类型相同,大小相等/* @file main.c @brief 线性结构之数组 @author EricsT (EricsT@163.com) @version v1.0.0 @date 202…

完整教程:Vue中的props方式

完整教程:Vue中的props方式pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco",…

深度剖析 B 站关键词排名:策略与技巧全解析 - 详解

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

图解25:MySQL主从复制原理

使用AI图生图,有些修饰的还不错,有些差强人意,特别是文字内容混在一起的AI明显是比较难处理

用 Go 编写验证码识别脚本(基于 Tesseract)

一、概述 识别验证码通常用于登录自动化、表单填写等自动化流程中。对于字符清晰、干扰较少的验证码,OCR 是一种轻便高效的识别方式。本文介绍如何使用 Go 调用 Tesseract OCR 实现验证码图片的识别。 二、前提条件安…

第03周 预习、实验与作业:面向对象入门2与类的识别

一、什么样的方法应该用static修饰?不用static修饰的方法往往具有什么特性?Student的getName应该用static修饰吗? (1)什么样的方法应该用static修饰? 1.工具类或者辅助方法 例如:Math.sqrt()、Arrays.sort()等,…

完整教程:MySQL 存储过程完整实战手册---一篇吃透 Stored Procedure

完整教程:MySQL 存储过程完整实战手册---一篇吃透 Stored Procedure2025-09-21 15:15 tlnshuju 阅读(0) 评论(0) 收藏 举报pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto …

数据结构 静态链表的实现(算法篇) - 详解

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

Zero-Shot、One-Shot、Few-Shot概念

Zero-Shot提示:模型只根据任务的描述生成响应,不需要任何示例。 One-Shot提示:只提供一个例子。 Few-Shot提示:提供几个例子。在提示中的作用是通过少量样本引导模型对特定任务进行学习和执行,例如通过提供少量风…

ADS放入元器件include和DK.zip文件依然提示未定义

ADS放入元器件include和DK.zip文件依然提示未定义各位ADS大佬,我在ads中导入CUSTOMER_ADS_V2005AP0806_PRJ.zip和图片中的这些文件(都是导入元器件模型和其中一个zip文件)都提示下面的截图,是我导入的顺序不对,还…