SPOJ DQUERY - D-query (莫队算法)
Given a sequence of n numbers a1, a2, ..., an and a number of d-queries. A d-query is a pair (i, j) (1 ≤ i ≤ j ≤ n). For each d-query (i, j), you have to return the number of distinct elements in the subsequence ai, ai+1, ..., aj.
Input
- Line 1: n (1 ≤ n ≤ 30000).
- Line 2: n numbers a1, a2, ..., an (1 ≤ ai ≤ 106).
- Line 3: q (1 ≤ q ≤ 200000), the number of d-queries.
- In the next q lines, each line contains 2 numbers i, j representing a d-query (1 ≤ i ≤ j ≤ n).
Output
- For each d-query (i, j), print the number of distinct elements in the subsequence ai, ai+1, ..., aj in a single line.
Example
Input 5 1 1 2 1 3 3 1 5 2 4 3 5Output 3 2 3
题意:有n个数,m个询问,每次询问l,r区间内有多少个不同的数。
这题作为莫队算法的入门题再好不过了,我们就借这题来讲解一下莫队算法。
莫队算法是用来解决离线查询的一种算法,主要思想就是借助前一次查询的结果,把区间向左向右伸缩推出下一个查询的结果。
利用两个指针分别指向区间的左端点和右端点,然后通过左移或者右移指针得到下一个区间的答案。
当然直接按询问的循序来进行指针的跳跃肯定是不行的,这样的复杂度最终会达到n^2,我们得采取一点技巧:
我们可以把整个区间分成一个一个块(每块大小为sqrt(n),一共有W块,W = n/sqrt(n)),然后先按照询问左端点所属的块数从小到大排序,如果所属块数相同,那么再按右端点大小从小到大排序,这样复杂度就降了下来。
我们来计算一下复杂度:
先看左端点,如果上次询问的左端点和这一次的左端点在同一个块,那么最多只要移动sqrt(n)次,如果不在一个块,最多要移动n次,这样m个询问一平均,就是常数了,所以左端点平均为sqrt(n)次
右端点:右端点只有在左端点在同一块内的时候才是有序的,其他的时候是不可控制的,所以右端点每次最坏情况是移动n次,
但是这种情况只会发生 W 次,可以把n,m看成同一级的,所以右端点的复杂度 n*n/sqrt(n)
所以总复杂度就为O(n*n/sqrt(n)) 即 O (n^(1.5))
有了上面的思想之后,其实代码还是比较简单的,主要部分就四个while,用来伸缩左右端点。
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define LL long longusing namespace std;struct query
{int id,l,r,ans;
}q[200010];int a[30010];
int f[1000010];
int W;
int cnt;int li(int x)
{return (x-1)/W + 1;
}
bool cmp1(query a,query b)
{if(li(a.l) == li(b.l))return a.r < b.r;return a.l < b.l;
}bool cmp2(query a,query b)
{return a.id < b.id;
}void add(int x)
{f[a[x]]++;if(f[a[x]] == 1)cnt++;
}void del(int x)
{f[a[x]]--;if(f[a[x]] == 0)cnt--;
}
int main(void)
{int n,m,i,j;while(scanf("%d",&n)==1){W = sqrt(n); //块的大小for(i=1;i<=n;i++)scanf("%d",&a[i]);scanf("%d",&m);for(i=1;i<=m;i++){scanf("%d%d",&q[i].l,&q[i].r);q[i].id = i;}sort(q+1,q+m+1,cmp1);memset(f,0,sizeof(f));int l = 1,r = 0;cnt = 0;for(i=1;i<=m;i++){while(r < q[i].r) add(++r); //添加右端点while(r > q[i].r) del(r--); //删除右端点while(l < q[i].l) del(l++); //删除左端点while(l > q[i].l) add(--l); //添加左端点q[i].ans = cnt;}sort(q+1,q+m+1,cmp2);for(i=1;i<=m;i++)printf("%d\n",q[i].ans);}return 0;
}
SPOJ DQUERY - D-query (莫队算法)相关推荐
- 莫队算法 (普通莫队、带修莫队、树上莫队)
莫队算法 主要基于分块的思想 用结构体记录询问的左右端点及询问编号 (这是一个离线算法) 通过排序优化指针扫描顺序优化时间复杂度 . 1.普通莫队 例题:SP3267 DQUERY - D-query ...
- BZOJ 2038: [2009国家集训队]小Z的袜子(hose)【莫队算法裸题学习笔记】
2038: [2009国家集训队]小Z的袜子(hose) Time Limit: 20 Sec Memory Limit: 259 MB Submit: 9894 Solved: 4561 [Su ...
- C++ 莫队算法(转)
胡小兔的良心莫队教程:莫队.带修改莫队.树上莫队 在开始学习莫队之前,照例先甩一道例题:BZOJ 1878 HH的项链. 题意:求区间内数的个数,相同的数只算一次. 在我关于这道题的上一篇题解中,我使 ...
- hdu 4358(莫队算法+dfs序列)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4358 解题思路:用dfs求出整棵树的dfs序列,这样以u为根节点的子树就转化到相对应的区间上了.由于是 ...
- hdu 5213(容斥原理+莫队算法)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5213 莫队算法是离线处理一类区间不修改查询类问题的算法.就是如果你知道了[L,R]的答案.你可以在O( ...
- 莫队算法 ( MO's algorithm )
莫队算法是由清华大学神牛莫涛发明的一种处理区间问题的离线算法 算法核心是通过先将问询区间总长度平方分块.然后将所有的问询区间按照左端点所在的块编号排序.在同一块内的则按右端点升序 然后设置左右两个下标 ...
- hdu 5145 NPY and girls (莫队算法)
题意:有一个长度为n的数字序列,m次询问一个区间l-r中数字重新排列的方案数(mod 10^9+7). 明显的莫队算法,只需要排序,然后预处理一下逆元就可以了. 所谓的莫队算法,最初版本是求曼哈顿距离 ...
- 曼哈顿距离最小生成树莫队算法
参考资料:https://www.cnblogs.com/CsOH/p/5904430.html https://blog.csdn.net/huzecong/article/details/8576 ...
- 莫队算法二(树上莫队cot2,Haruna’s Breakfast)
例一:不带修改 Count on a tree II Time Limit: 1207MS Memory Limit: 1572864KB 64bit IO Format: %lld & ...
最新文章
- 利用 Python 打造一个语音合成系统
- 【设计模式】—— 中介者模式Mediator
- Oracle入门(七B)之表空间删除数据文件未删除
- 网络协议之http和tcp思维导图
- uboot之源码目录分析
- 信息学奥赛一本通(2064:【例2.1】交换值)
- fatal error: Eigen3/Core: 没有那个文件或目录
- 打造专业人才发展链条:基于任职资格的专业人才发展与认证体系
- android wpa2 wifi,让Android WiFi支持中文
- Swift网络开发之NSURLSession学习笔记
- Linux学习之旅(二)Linux文档操作
- 使用人人开源遇到的bug
- linux tomcat6安装及配置
- OSI常用网络协议(七层)
- 神经网络压缩 剪枝 量化 嵌入式计算优化NCNN mobilenet squeezenet shufflenet
- 菌群多样性是如何形成的,与健康的关系,如何改善?
- 小米4 第三方re奇兔_小米推送测试
- 网站服务器商标属于哪类,网络平台商标注册属于什么类别?-商标分类表-猪八戒知识产权...
- 为什么onenote一直在加载_2.为什么人人都需要OneNote?
- 计算机科学的一个字节是几位,什么是字节--字节换算