[洛谷 P1972] HH的项链(SDOI2009)
P1972 [SDOI2009]HH的项链
题目描述
HH 有一串由各种漂亮的贝壳组成的项链。HH 相信不同的贝壳会带来好运,所以每次散步完后,他都会随意取出一段贝壳,思考它们所表达的含义。HH 不断地收集新的贝壳,因此,他的项链变得越来越长。有一天,他突然提出了一个问题:某一段贝壳中,包含了多少种不同的贝壳?这个问题很难回答……因为项链实在是太长了。于是,他只好求助睿智的你,来解决这个问题。
输入输出格式
输入格式:
第一行:一个整数N,表示项链的长度。
第二行:N 个整数,表示依次表示项链中贝壳的编号(编号为0 到1000000 之间的整数)。
第三行:一个整数M,表示HH 询问的个数。
接下来M 行:每行两个整数,L 和R(1 ≤ L ≤ R ≤ N),表示询问的区间。
输出格式:
M 行,每行一个整数,依次表示询问对应的答案。
输入输出样例
6 1 2 3 4 3 5 3 1 2 3 5 2 6
2 2 4
说明
数据范围:
对于100%的数据,N <= 50000,M <= 200000。
莫队第一A。先膜拜一下莫涛dalao%%%,创造了这个算法。
既然是第一次做莫队,那就顺便讲讲吧。
----------------------------------------------^_^---------------------------------------------
据说,莫队能解决一切区间问题(超强),不过当然要配合着其他一些算法。下面是一个区间询问问题:
给定一个大小为N的数组,数组中所有元素的大小<=N。你需要回答Q个询问。每个询问会给出范围L,R。你需要回答在[ L,R ]中至少出现2次的数字的个数。
如:数组为{ 4,2,1,3,2,2,4,1,1,3 } 查询:L=2,R=5。答案=1。在范围[L,R]中:{ 2,1,3,2 },只有2是出现至少2次的。
对于这个问题,显然我们有一个n^2的暴力可以写
for each query:
answer = 0 count[] = 0
for i in {l..r}:
count[array[i]]++
if count[array[i]] == 2: answer++
显然,在最坏情况下是n^2的。我们对此进行一下改进:
add(position):
count[array[position]]++
if count[array[position]] == 2:
answer++
remove(position):
count[array[position]]--
if count[array[position]] == 1:
answer--
currentL = 0
currentR = 0
answer = 0
count[] = 0
for each query:
// currentL 应当到 L, currentR 应当到 R
while currentL < L: remove(currentL) currentL++
while currentL > L: add(currentL) currentL--
while currentR < R: add(currentR) currentR++
while currentR > R: remove(currentR) currentR--
output answer
这个算法理论上是n^2的,但是实际运行时还是有所改善的。
最初我们总是从L至R循环,但现在我们从上一次查询的位置调整到当前的查询的位置。
如果上一次的查询是L = 3,R = 10,则我们在查询结束时有currentL=3、currentR=10。如果下一个查询是L = 5,R = 7,则我们将currentL 移动到5,currentR 移动到7。
add 函数 意味着我们添加该位置的元素到当前集合内,并且更新相应的回答。
remove 函数 意味着我们从当前集合内移除该位置的元素,并且更新相应的回答。
接下来就是强大的莫队算法登场了。
莫队算法仅仅调整我们处理查询的顺序(所以前面的铺垫尤为重要!)。
我们得到了Q个查询,我们将把查询以一个特定的顺序进行重新排序,然后处理它们。
显然,这是一个离线算法。每个查询都有L和R,我们称其为“起点”和“终点”。让我们将给定的输入数组分为根号n块。每一块的大小为 根号n。每个“起点”落入其中的一块。每个“终点”也落入其中的一块。
如果某查询的“起点”落在第p块中,则该查询属于第p块。该算法将处理第1块中的查询,然后处理第2块中的查询,等等,最后直到第根号n块。
至此,我们已经有一个顺序、查询按照所在的块升序排列,因此可以有很多的查询属于同一块。
从现在开始,忽略所有的块,只关注我们如何询问和回答第1块。我们将对所有块做同样的事。(第1块中的)所有查询的“起点”属于第1块,但“终点”可以在包括第1块在内的任何块中。
现在让我们按照R值升序的顺序重新排列这些查询。我们也在所有的块中做这个操作。(指每个块块内按R升序排列。)
最终的排序是怎样的?
所有的询问首先按照所在块的编号升序排列(所在块的编号是指询问的“起点”属于的块)。如果编号相同,则按R值升序排列。
例如考虑如下的询问,假设我们会有3个大小为3的块(0-2,3-5,6-8):{0, 3} {1, 7} {2, 8} {7, 8} {4, 8} {4, 4} {1, 2}
让我们先根据所在块的编号重新排列它们{0, 3} {1, 7} {2, 8} {1, 2}(|){4, 8} {4, 4}(|){7, 8}
现在我们按照R的值重新排列 {1, 2} {0, 3} {1, 7} {2, 8}(|){4, 4} {4, 8}(|){7, 8}
现在我们使用与上一节所述相同的代码来解决这个问题。上述算法是正确,因为我们没有做任何改变,只是重新排列了查询的顺序。
至此,我们完成了莫队算法,它只是一个重新排序。
可怕的是它的时间复杂度分析。原来,如果我们按照上面指定的顺序,我们所写的O(N^2)的代码运行在O(N根号N)时间复杂度上,那这就挺完美了。(证明略)
(参考资料:MO’s Algorithm (Query square root decomposition),作者anudeep2011,发表日期为2014-12-28)
----------------------------------------------^_^---------------------------------------------
那么回到题目,我们发现,这就是一道模板题罢了。。。=_=
#include<cstdio> #include<cstring> #include<algorithm> #include<cmath> using namespace std; ],c[],ans; struct query{ int L,R,index,ans; }a[]; inline int read(){ ; char ch=getchar(); ') ch=getchar(); +ch-',ch=getchar(); return x; } bool cmp(query u,query v){return u.L/blocks==v.L/blocks?u.R<v.R:u.L<v.L;} bool cmp_id(query u,query v){return u.index<v.index;} );} );} int main(){ n=read(),blocks=sqrt(n); ; i<=n; i++) c[i]=read(); Q=read(); ; i<=Q; i++) a[i].L=read(),a[i].R=read(),a[i].index=i; sort(a+,a++Q,cmp); ,curR=; memset(cnt,,; ; i<=Q; i++){ while (curL<a[i].L) remove(curL++); while (curR>a[i].R) remove(curR--); while (curL>a[i].L) add(--curL); while (curR<a[i].R) add(++curR); a[i].ans=ans; } sort(a+,a++Q,cmp_id); ; i<=Q; i++) printf("%d\n",a[i].ans); ; }
[洛谷 P1972] HH的项链(SDOI2009)的更多相关文章
- 洛谷P1972 HH的项链【树状数组】
题目:https://www.luogu.org/problemnew/show/P1972 题意:给定一个长度为n的序列,数字表示珠子的种类.m次查询每次询问给定区间内珠子的种类数. 思路:可以说是 ...
- 洛谷P1972 HH的项链
传送门啦 分析: 题目描述不说了,大意是,求一段区间内不同元素的种数. 看到区间,我们大概先想到的是暴力(然后炸掉).线段树.树状数组.分块. 下面给出的是一种树状数组的想法. 首先,对于每一段区间里 ...
- 洛谷 P1972 HH的项链 题解
题面 本题其实主要就这几点: 1.离线,以右端点排序(从小到大); 2.建立树状数组c[],c[i]表示从1~i中有多少种不同的数字: 3.对于每次查询的答案就是sum(r)-sum(l-1); 4. ...
- BZOJ1878 洛谷1972 HH的项链题解
洛谷链接 BZOJ链接 看到这样不用修改的题目,应该佷容易就联想到了离线来处理. 我们发现若将询问按照r来排序,排完后每次对答案有贡献的仅是每个颜色最后出现的位置 我们用next[i]表示i处颜色之前 ...
- 洛谷1972 HH的项链 树状数组查询区间内不同的数的数量
题目链接:https://www.luogu.com.cn/problem/P1972 题意大致是:给定一个序列长度为n,给出m个查询区间,要求响应是区间内不同的数的个数.为此我们考虑到树状数组的区间 ...
- 洛谷P1972 [SDOI2009]HH的项链 题解
[SDOI2009]HH的项链 题目背景 无 题目描述 HH 有一串由各种漂亮的贝壳组成的项链.HH 相信不同的贝壳会带来好运,所以每次散步完后,他都会随意取出一段贝壳,思考它们所表达的含义.HH 不 ...
- 洛谷 P1972 [SDOI2009]HH的项链【莫队算法学习】
P1972 [SDOI2009]HH的项链 题目背景 无 题目描述 HH 有一串由各种漂亮的贝壳组成的项链.HH 相信不同的贝壳会带来好运,所以每次散步完后,他都会随意取出一段贝壳,思考它们所表达的含 ...
- 洛谷 P1972 [SDOI2009]HH的项链 解题报告
P1972 [SDOI2009]HH的项链 题目描述 HH 有一串由各种漂亮的贝壳组成的项链.HH 相信不同的贝壳会带来好运,所以每次散步完后,他都会随意取出一段贝壳,思考它们所表达的含义.HH 不断 ...
- 洛谷——P1972 [SDOI2009]HH的项链(线段树)
P1972 [SDOI2009]HH的项链 HH 有一串由各种漂亮的贝壳组成的项链.HH 相信不同的贝壳会带来好运,所以每次散步完后,他都会随意取出一段贝壳,思考它们所表达的含义.HH 不断地收集新的 ...
随机推荐
- 运行python脚本后台执行
最近搞到了一台服务器,挂一个脚本刷刷河畔在线时间.脚本随便写了两下,能跑到什么时候就随缘了 https://blog.csdn.net/philosophyatmath/article/details ...
- 5、web站点架构模式简介及Nginx
LB Cluster: 提升系统容量的方式: scale up:向上扩展 scale out:向外扩展 LVS工作在内核中,本身的数量不受套接字数量限制,利用LVS做调度器,优化得当的话,并发数量可以 ...
- 新建DataTable添加列添加行
新建空Table添加行和列 DataTable dt = new DataTable(); //创建空DataTable 1.添加列 dt.Columns.Add("序号", ty ...
- spring boot配置druid数据源和监控配置
直接上代码: 一.pom.xml中添加依赖 <dependency> <groupId>com.github.drtrang</groupId> <artif ...
- 实现一个优先级队列,每次pop 返回优先级最高的元素
demo1 实现一个按优先级排序的队列, 并且在这个队列上面每次 pop 操作总是返回优先级最高的那个元素 import heapq class PriorityQueue: def __init__ ...
- ege demo
#include <ege.h> const float base_speed = 0.5f; const float randspeed = 1.5f; //自定义函数,用来返回一个0 ...
- 1. eclipse异常问题解决办法
1. 内存溢出问题 问题描述:报错信息 java.lang.OutOfMemoryError: PermGen space 解决办法: 在Tomcat/bin/catalina.bat 文件下加入: ...
- Python3 数据库连接
PyMySQL是在Python3.x版本中用于连接MySQL服务器的一个库,Python2中使用mysqldb. 数据库连接 连接数据库前,请先确认一下事项: 已经创建数据库testdb. 在test ...
- kbengine学习1 安装
KBengine一年前就知道了,但是没来得及学(只记得是C++ + python脚本),前一个项目unity3d+fkask+socketio+sqlite硬怼出来的.这半年也没来得及管.(好像当时看 ...
- Python全栈开发-Day12-Mysql数据库和ORM
本节内容 数据库介绍 mysql 数据库安装使用 mysql管理 mysql 数据类型 常用mysql命令 创建数据库 外键 增删改查表 权限 事务 索引 python 操作mysql ORM sql ...