【一百一十】【算法分析与设计】[SDOI2009] HH的项链,树状数组应用,查询区间的种类数,树状数组查询区间种类数

news2025/4/8 15:01:19

P1972 [SDOI2009] HH的项链

[SDOI2009] HH的项链

题目描述

HH 有一串由各种漂亮的贝壳组成的项链。HH 相信不同的贝壳会带来好运,所以每次散步完后,他都会随意取出一段贝壳,思考它们所表达的含义。HH
不断地收集新的贝壳,因此,他的项链变得越来越长。

有一天,他突然提出了一个问题:某一段贝壳中,包含了多少种不同的贝壳?这个问题很难回答……
因为项链实在是太长了。于是,他只好求助睿智的你,来解决这个问题。

输入格式

一行一个正整数 n n n,表示项链长度。 第二行 n n n 个正整数 a i a_i ai,表示项链中第 i i i 个贝壳的种类。

第三行一个整数 m m m,表示 HH 询问的个数。 接下来 m m m 行,每行两个整数 l , r l,r l,r,表示询问的区间。

输出格式

输出 m m m 行,每行一个整数,依次表示询问对应的答案。

样例 #1

样例输入 #1

6 1 2 3 4 3 5 3 1 2 3 5 2 6

样例输出 #1

2 2 4

提示

【数据范围】

对于 20 % 20\% 20% 的数据, 1 ≤ n , m ≤ 5000 1\le n,m\leq 5000 1n,m5000; 对于 40 % 40\% 40% 的数据, 1 ≤ n , m ≤ 1 0 5 1\le n,m\leq 10^5 1n,m105; 对于 60 % 60\% 60% 的数据, 1 ≤ n , m ≤ 5 × 1 0 5 1\le n,m\leq 5\times 10^5 1n,m5×105; 对于 100 % 100\% 100%
的数据, 1 ≤ n , m , a i ≤ 1 0 6 1\le n,m,a_i \leq 10^6 1n,m,ai106 1 ≤ l ≤ r ≤ n 1\le l \le r \le n 1lrn

本题可能需要较快的读入方式,最大数据点读入数据约 20MB

在这里插入图片描述
用count数组记录每一个位置种类数,实际上每一个位置都算作是1.
如果每一个位置都是1.
在这里插入图片描述
计算1~ 4区间的种类数是1~ 4区间count数组的累加和结果.
因为1~ 4区间中的种类数全部都没有出现重复的情况.
但是如果要计算3~ 5区间的种类数是多少,那么就需要对3和5哪一个位置进行去重的处理.

如果我们查询的区间是l~ r.
在这里插入图片描述
1表示重复的种类的1出现的位置,那么打叉的地方是需要进行去重的,打勾的地方是可以选择保留的地方.
针对于第三种情况,r右边出现的1我们并不关心,因为一定不在查询区间中.
因此可以按照查询的右区间从小到大排序,只维护r左边count值即可.
现在我们就只需要维护好r左边的count值就可以了.
也就是第一种情况和第二种情况,第二种情况因为都在区间内,所以不管去掉哪一个都可以,但是第一种情况只能去掉左边的.
因此我们可以按照这样的规则,只保留最右边的1.因为如果包含最右边的1,其他的可以被代替,如果没有包含最右边的1,其他的1也没有意义.
所以只需要关心最右边的1即可.

按照查询的右区间进行排序,然后只维护r左边的count值.
当前位置是i=1位置,然后维护1~ r区间的count值,每一次都添加1,但是每一次遍历i位置的时候需要考虑是否需要去重操作.
也就是需要查询arr[i]元素最右侧的1是否出现,如果出现了就需要先减少1.

在这里插入图片描述
第一次查询结果是count数组1~ 2累加和,答案是2
在这里插入图片描述
当i遍历到5的时候,我们查询map_left发现5位置的元素3之前出现过,位置是3,所以需要进行去重操作,将3位置count值减少1,然后5位置count值增加1.并且将维护arr_left值,元素3最右边的下标是5.
在这里插入图片描述
此时查询3~ 5区间的种类数是count3~ 5区间累加和,答案是2.
在这里插入图片描述
查询2~ 6区间的种类数,也就是count2~ 6区间累加和,答案是4.

#include<bits/stdc++.h>
using namespace std;

#define int long long // 将 int 定义为 long long 类型
#define endl '\n' // 将 endl 定义为换行符

int n; // 定义整数 n,表示数组长度
vector<int>arr; // 定义一个整型向量 arr,用于存储数组元素
int q; // 定义整数 q,表示查询次数
struct node {
	int l, r, index; // 定义结构体 node,包含三个整型变量 l, r 和 index
};
vector<node>readd; // 定义一个 node 类型的向量 readd,用于存储查询
map<int, int>arr_left; // 定义一个映射 arr_left,用于记录元素上次出现的位置
class Tree {
public:
	vector<int>tree; // 定义一个整型向量 tree,用于树状数组
	int lowbit(int i) { // 返回 i 的最低位 1 的值
		return i & -i;
	}
	void sett(int i, int v) { // 在树状数组中更新值
		while (i < tree.size()) {
			tree[i] += v;
			i += lowbit(i);
		}
	}
	int gett(int i) { // 获取前 i 项的和
		int ret = 0;
		while (i > 0) {
			ret += tree[i];
			i -= lowbit(i);
		}
		return ret;
	}

	int range(int l, int r) { // 获取区间 [l, r] 的和
		return gett(r) - gett(l - 1);
	}
};
Tree t1; // 定义一个 Tree 类的对象 t1
void init() { // 初始化函数
	cin >> n; // 输入数组长度
	arr.assign(n + 1, 0); // 将数组大小设为 n+1,并初始化为 0
	for (int i = 1; i <= n; i++) {
		cin >> arr[i]; // 输入数组元素
	}
	readd.clear(); // 清空 readd 向量
	cin >> q; // 输入查询次数
	for (int i = 1; i <= q; i++) {
		int l, r;
		cin >> l >> r; // 输入每个查询的左右边界
		readd.push_back({ l,r,i }); // 将查询添加到 readd 向量中
	}
}
vector<int>ret; // 定义整型向量 ret,用于存储结果
void solve() {
	sort(readd.begin(), readd.end(), [](const node& a, const node& b) { // 按照查询的右边界 r 进行排序
		return a.r < b.r;
		});
	ret.assign(q + 1, -1); // 将 ret 大小设为 q+1,并初始化为 -1
	t1.tree.assign(arr.size() + 1, 0); // 初始化树状数组
	arr_left.clear(); // 清空 arr_left 映射
	int i = 1;
	for (auto& xx : readd) {
		int l = xx.l, r = xx.r, index = xx.index; // 取出每个查询的 l, r 和 index
		while (i <= r) {
			if (arr_left.count(arr[i])) { // 如果元素已在 arr_left 中记录过
				int index1 = arr_left[arr[i]]; // 取出上次出现的位置
				t1.sett(index1, -1); // 在树状数组中将该位置的值减 1
			}

			arr_left[arr[i]] = i; // 更新 arr_left 中该元素的最新位置
			t1.sett(i, 1); // 在树状数组中将当前元素位置的值加 1
			i++;
		}
		ret[index] = t1.range(l, r); // 计算区间 [l, r] 的和并存储在 ret 中
	}
	for (int i = 1; i < ret.size(); i++) {
		cout << ret[i] << endl; // 输出每个查询的结果
	}

}

signed main() {
	ios::sync_with_stdio(0), cin.tie(), cout.tie(0); // 加速输入输出

	init(); // 调用初始化函数
	solve(); // 调用解决函数
}

结尾

最后,感谢您阅读我的文章,希望这些内容能够对您有所启发和帮助。如果您有任何问题或想要分享您的观点,请随时在评论区留言。
同时,不要忘记订阅我的博客以获取更多有趣的内容。在未来的文章中,我将继续探讨这个话题的不同方面,为您呈现更多深度和见解。
谢谢您的支持,期待与您在下一篇文章中再次相遇!

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

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

相关文章

第十二届蓝桥杯C++青少年组中/高级组选拔赛2020年11月22日真题解析

一、编程题 第1题&#xff1a;求和 【题目描述】 输入一个正整数 N(N < 100)&#xff0c;输出 1 到 N(包含 1 和 N)之间所有奇数的和。 【输入描述】 输入一个正整数 N(N < 100) 【输出描述】 输出 1 到 N 之间的所有奇数的和 【输入样例】 3【输出样例】 4答案&…

Llama模型家族之拒绝抽样(Rejection Sampling)(九) 强化学习之Rejection Sampling

LlaMA 3 系列博客 基于 LlaMA 3 LangGraph 在windows本地部署大模型 &#xff08;一&#xff09; 基于 LlaMA 3 LangGraph 在windows本地部署大模型 &#xff08;二&#xff09; 基于 LlaMA 3 LangGraph 在windows本地部署大模型 &#xff08;三&#xff09; 基于 LlaMA…

利用streamlit结合langchain_aws实现claud3的页面交互

测试使用的代码如下 import streamlit as st from langchain_aws import ChatBedrockdef chat_with_model(prompt, model_id):llm ChatBedrock(credentials_profile_name"default", model_idmodel_id, region_name"us-east-1")res llm.invoke(prompt)re…

UiPath发送邮件给多人时需要注意哪些限制?

UiPath发送邮件给多人的步骤&#xff1f;如何使用UiPath发信&#xff1f; 尽管UiPath提供了强大的邮件发送功能&#xff0c;但在批量发送邮件时&#xff0c;有一些限制和注意事项是我们必须了解的。AokSend将详细介绍这些限制&#xff0c;并提供一些优化建议。 UiPath发送邮件…

视频监控管理平台LntonCVS视频汇聚平台充电桩视频监控应用方案

随着新能源汽车的广泛使用&#xff0c;公众对充电设施的安全性和可靠性日益重视。为了提高充电桩的安全管理和站点运营效率&#xff0c;LntonCVS公司推出了一套全面的新能源汽车充电桩视频监控与管理解决方案。 该方案通过安装高分辨率摄像头&#xff0c;对充电桩及其周边区域进…

纷享销客安全体系:安全合规认证

安全合规认证是指组织通过独立的第三方机构对其信息系统和数据进行评估和审查&#xff0c;以确认其符合相关的安全标准、法律法规和行业要求的过程。 安全合规认证可以帮助组织提高信息系统和数据的安全性&#xff0c;并向客户、合作伙伴和监管机构证明其符合相关的安全标准和…

python协程入门实战详解

本章将以通俗易懂、贴合实际的方式介绍以下内容&#xff1a; 协程是什么&#xff0c;有什么特点&#xff0c;协程的优势是什么如何理解事件和事件循环协程的创建方式&#xff0c;如何控制协程的并发量在协程中使用aiohttp发送HTTP请求aiohttp案例协程中的异常处理&#xff0c;…

如何使用Python的Turtle模块绘制小猪

一、前置条件 在开始学习如何使用Python的Turtle模块进行绘画之前&#xff0c;请确保你的电脑已安装Python环境。如果尚未安装Python&#xff0c;你可以从Python官网下载并安装最新版本。 Turtle模块是Python内置的一个用于绘图的库&#xff0c;通常不需要额外安装。如果你发…

使用 Ollama 和 Open WebUI 自托管 LLM 聊天机器人(无需 GPU)

✨点击这里✨&#xff1a;&#x1f680;原文链接&#xff1a;&#xff08;更好排版、视频播放、社群交流、最新AI开源项目、AI工具分享都在这个公众号&#xff01;&#xff09; 使用 Ollama 和 Open WebUI 自托管 LLM 聊天机器人&#xff08;无需 GPU&#xff09; &#x1f31…

linux指令--sed

sed 主要用来自动编辑一个或多个文件、简化对文件的反复操作、编写转换程序等。 语法解析 sed [选项] 编辑命令 文件 选项&#xff1a; -n&#xff1a;只显示匹配处理的行-e&#xff1a;执行多个编辑命令时-i&#xff1a;在原文件中进行修改&#xff0c;不输出到屏幕-…

Windows下对于Qt中带 / 的路径的处理

在Windows下&#xff0c;如果你想使用操作系统的分隔符显示用户的路径&#xff0c;请使用 toNativeSeparators()。 请看以下代码&#xff1a; void Player::on_playBtn_clicked() {if (this->m_url.isEmpty()) {openMedia();if (this->m_url.isEmpty())return;}qDebug(…

机器学习作业6——svm支持向量机

目录 一、理论 概念&#xff1a; 线性可分&#xff1a; 支持向量&#xff1a; 间隔&#xff1a; 目标&#xff1a; 软间隔&#xff1a; 梯度下降法&#xff1a; 别的方法&#xff1a; 拉格朗日函数&#xff1a; SMO算法&#xff1a; 核函数&#xff1a; 二、代码 …

数据结构之ArrayList与顺序表(下)

找往期文章包括但不限于本期文章中不懂的知识点&#xff1a; 个人主页&#xff1a;我要学编程(ಥ_ಥ)-CSDN博客 所属专栏&#xff1a;数据结构&#xff08;Java版&#xff09; 目录 ArrayList的具体使用 118. 杨辉三角 扑克洗牌算法 接上篇&#xff1a;数据结构之ArrayLis…

三端植物大战僵尸杂交版来了

Hi&#xff0c;好久不见&#xff0c;最近植物大战僵尸杂交版蛮火的 那今天苏音整理给大家三端的植物大战僵尸杂交版包括【苹果端、电脑端、安卓端】 想要下载的直接划到最下方即可下载。 植物大战僵尸&#xff0c;作为一款古老的单机游戏&#xff0c;近期随着B站一位UP主潜艇…

英伟达黄仁勋最新主题演讲:“机器人时代“已经到来

6月2日&#xff0c;英伟达联合创始人兼首席执行官黄仁勋在Computex 2024&#xff08;2024台北国际电脑展&#xff09;上发表主题演讲&#xff0c;分享了人工智能时代如何助推全球新产业革命。 黄仁勋表示&#xff0c;机器人时代已经到来&#xff0c;将来所有移动的物体都将实现…

开源与新质生产力

在这个信息技术迅猛发展的时代&#xff0c;全球范围内的产业都在经历着深刻的变革。在这样的背景下&#xff0c;“新质生产力”的概念引起了广泛的讨论。无论是已经成为或正努力转型成为新质生产力的企业&#xff0c;都在寻求新的增长动力和竞争优势。作为一名长期从事开源领域…

什么是2+1退休模式?什么是链动2+1模式?

21退休模式又称链动21模式&#xff0c;主要是建立团队模式&#xff0c;同时快速提升销量。是目前成熟模式中裂变速度最快的模式。21退休模式合理合规&#xff0c;同时激励用户公司的利润分享机制&#xff0c;让您在享受购物折扣的同时&#xff0c;也能促进并获得客观收益。 模…

kettle从入门到精通 第六十六课 ETL之kettle kettle阻塞教程,轻松获取最后一行数据,so easy

场景:ETL沟通交流群内有小伙伴反馈,如何在同步一批数据完成之后记录下同步结果呢?或者是调用后续步骤、存储过程、三方接口等。 解决:使用步骤Blocking step进行阻塞处理即可。 1、下面的demo演示从表t1同步数据至表t2(t1表中有三条数据,t2为空表,两个表表结构相同),…

Plotly : 超好用的Python可视化工具

文章目录 安装&#xff1a;开始你的 Plotly 之旅基本折线图&#xff1a;简单却强大的起点带颜色的散点图&#xff1a;数据的多彩世界三维曲面图&#xff1a;探索数据的深度气泡图&#xff1a;让世界看到你的数据小提琴图&#xff1a;数据分布的优雅展现旭日图&#xff1a;分层数…

Vue学习day05笔记

day05 一、学习目标 1.自定义指令 基本语法&#xff08;全局、局部注册&#xff09;指令的值v-loading的指令封装 2.插槽 默认插槽具名插槽作用域插槽 3.综合案例&#xff1a;商品列表 MyTag组件封装MyTable组件封装 4.路由入门 单页应用程序路由VueRouter的基本使用 …