[洛谷 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 不断地收集新的 ...
随机推荐
- 给大家讲个故事,感受一下什么叫CF。不知道的请认真听。
我朋友是个温柔.体贴.负责.做事认真和口才流利的好男人 他在大一时喜欢上别系的女同学,像他这样的好人我以为这段恋情是手到擒来 但并没有,女方只把它当工具人,一当就当了四年 身为室友的我每天看著她为女方 ...
- 1、Keepalived及VRRP原理介绍
keepalived:即在linux中vrrp协议的实现 http://www.keepalived.org/ 什么是Keepalived? Keepalived是一个用C语言编写的路由软件.该项目 ...
- KNN——图像分类
内容参考自:https://zhuanlan.zhihu.com/p/20894041?refer=intelligentunit 用像素点的rgb值来判断图片的分类准确率并不高,但是作为一个练习kn ...
- react native 第三方组件react-native-swiper 轮播组件
github地址:https://github.com/leecade/react-native-swiper 使用方法:安装:npm i react-native-swiper –save 查看模块 ...
- 前端单页面富应用(SPA)的实现
一. 什么是单页面富应用? 单页面应用:Single Page Application 概念:Web应用即使不刷新也在不同的页面间切换,解决浏览器前进.后退等机制被破坏等问题.并且页面访问会被浏览器保 ...
- linux系统磁盘使用情况
#!/bin/bash total_disk=`df -k | grep -v Filesystem | awk '{print int($2)}'` available_disk=`df -k | ...
- vue自定义错误界面
方案一: 当输入错误链接错误或者找不到页面,在router里可以定义一个404页面,具体可以这样做:在routes里面这样写: { path:'*', component:error, name:'e ...
- HDUOJ 不容易系列之(4)——考新郎
题目链接http://acm.hdu.edu.cn/showproblem.php?pid=2049 一开始我的想法就是使用错排公式,先使用全排列从N对中选出M对,然后再使用错排对选出的M对进行错排计 ...
- Codeforces 797C - Minimal string
C. Minimal string 题目链接:http://codeforces.com/problemset/problem/797/C time limit per test 1 second m ...
- h5屏幕旋转的时间和样式的设置
好几天没更新博客了,今天写写小感悟和一个小东西吧! 随着前端的前端的越来越火,对前端的要求也越来越高,从之前的切图到开发网站再到现在移动端开发,微信开发,手机app混合开发,不得不说现在前端在开发行业 ...