[洛谷 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 open 对应的参数
- Spring-JDBC依赖
<dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</a ...
- SMTP发送邮件
SMTP是发送邮件的协议,Python内置对SMTP的支持,可以发送纯文本邮件.HTML邮件以及带附件的邮件. Python对SMTP支持有smtplib和email两个模块,email负责构造邮件, ...
- 七牛云存储上传自有证书开启https访问
虽然七牛云存储也提供免费SSL证书申请,但我就喜欢用其他平台申请的,于是在腾讯云申请了免费SSL证书,正准备在七牛上传,弹出的界面却让我傻了眼,如下图所示: 腾讯免费SSL证书提供了不同服务器环境的版 ...
- Selenium IDE使用
基于版本Selenium IDE 3.2.2(注:该工具不常用,可以使用定位元素是否存在) Selenium IDE可以录制也很方便,当然录下来的经常回放不成功,需要自己调试就是了.它是只针对Web页 ...
- Ubuntu 追加组,用户,设置免sudo密码输入
1,以root权限执行groupadd命令创建dev组. sudo groupadd dev 2,用adduser命令创建bpuser用户,--ingroup指定用户加入dev组. sud ...
- Lua和C++交互 学习记录之三:全局值交互
主要内容转载自:子龙山人博客(强烈建议去子龙山人博客完全学习一遍) 部分内容查阅自:<Lua 5.3 参考手册>中文版 译者 云风 制作 Kavcc vs2013+lua-5.3.3 1 ...
- Codeforces 1016 E - Rest In The Shades
E - Rest In The Shades 思路: 相似 红色的长度等于(y - s) / y 倍的 A' 和 B' 之间的 fence的长度 A' 是 p 和 A 连线和 x 轴交点, B'同理 ...
- Axure 元件的移动效果
元件的移动主要是指当点击某一元件(登录)时,某些元件会发生移动或者是左右移动的动画效果,先将登录界面设置为动态面板,然后再设置动作 本节主要应用于一下三种场景: 1.当邮箱不为空.密码为空时,点击登录 ...
- legend2---开发日志5(如何解决插件的延迟问题,比如vue)
legend2---开发日志5(如何解决插件的延迟问题,比如vue) 一.总结 一句话总结:元素可以先设置为隐藏,这样就不会让用户看到延迟的问题,然后等加载完再显示, 元素先设置为隐藏 加载完再显示 ...