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 5 Output
3
2
3 题意:给你一段区间,q个询问,询问区间[l,r]有多少个不同的数字
思路: 这道题算是很有意思的一道数据结构题了。。解法很多:莫队,主席树,离线树状数组都可以。解法也不难。 莫队解法:
思路:这道题感觉就是直接莫队莽上就完事了,没有什么需要处理的,就维护下每个元素在当前区间出现的次数就好了。
实现代码:
#include<bits/stdc++.h>
using namespace std; const int M = 1e6 + ;
int a[M],num[M],vis[M],block,ans = ,n,m;
struct node{
int l,r,id;
bool operator < (const node &cmp) const{
if(l/block == cmp.l/block) return r < cmp.r;
return l/block < cmp.l/block;
}
}q[M]; void add(int x){
vis[a[x]]++;
if(vis[a[x]] == ) ans++;
} void del(int x){
vis[a[x]]--;
if(vis[a[x]] == ) ans--;
} int main()
{
scanf("%d",&n);
block = sqrt(n);
for(int i = ;i <= n;i ++){
scanf("%d",&a[i]);
}
scanf("%d",&m);
for(int i = ;i <= m;i ++){
scanf("%d%d",&q[i].l,&q[i].r);
q[i].id = i;
}
sort(q+,q+m+);
int l = ,r = ;
for(int i = ;i <= m;i ++){
while(l < q[i].l) del(l),l++;
while(l > q[i].l) l--,add(l);
while(r < q[i].r) r++,add(r);
while(r > q[i].r) del(r),r--;
num[q[i].id] = ans;
}
for(int i = ;i <= m;i ++)
printf("%d\n",num[i]);
return ; }

ps:

使用莫队算法耗时为:270ms;

主席树解法:

我们将元素在序列中的地址建成主席树,如果这个元素没有出现过,那么就在这个位置上+1,如果这个元素出现过那就将这个元素上一次出现的位置-1,在当前位置+1;每棵线段树维护的都是1到当前

位置的不同元素的个数。

实现代码:

#include<bits/stdc++.h>
using namespace std; const int M = 3e4+;
const int Max = 1e6+;
int rs[M*],ls[M*],sum[M*],root[M*];
int a[M],idx;
int vis[Max],ret; void update(int old,int &k,int l,int r,int p,int c){
k = ++idx;
ls[k] = ls[old]; rs[k] = rs[old]; sum[k] = sum[old] + c;
if(l == r) return ;
int mid = (l + r) >> ;
if(p <= mid) update(ls[old],ls[k],l,mid,p,c);
else update(rs[old],rs[k],mid+,r,p,c);
} void query(int k,int l,int r,int p){
if(p == l){
ret += sum[k];
return ;
}
int mid = (l + r) >> ;
if(p <= mid) ret += sum[rs[k]],query(ls[k],l,mid,p);
else query(rs[k],mid+,r,p);
return ;
} int main()
{
int n,q;
scanf("%d",&n);
idx = ;
for(int i = ;i <= n;i ++) scanf("%d", &a[i]);
memset(vis,,sizeof(vis));
for(int i = ;i <= n;i ++){
int tmp = ;
if(!vis[a[i]]) update(root[i-],root[i],,n,i,);
else {
update(root[i-],tmp,,n,vis[a[i]],-);
update(tmp,root[i],,n,i,);
}
vis[a[i]] = i;
}
scanf("%d",&q);
while(q--){
int l,r;
scanf("%d %d",&l,&r);
ret = ;
query(root[r],,n,l);
printf("%d\n",ret);
}
return ;
}

ps:

主席树耗时为:200ms;

离线+树状数组

先离线下,对询问的r排序,以元素的下标作树状数组维护以r为右边界的区间不同元素的数量,遍历时如果当前元素没有出现,那么存在他的地址,并在树状数组对应下标+1,如果这个元素

之前已经出现过了,那么取消之前标记的点也就是将这个元素上一次出现的下标在树状数组中-1,变成0,然后再储存下当前元素最迟出现的下标,也就是当前点。

最后区间[l,r]之间不同的数量也就是sumR - sumL;

实现代码:

#include<bits/stdc++.h>
using namespace std; const int Max = 1e6+;
int c[Max],a[Max],n,m,ans[Max],mp[Max];
int lowbit(int x){
return x&(-x);
} int getsum(int x){
int sum = ;
while(x>){
sum += c[x];
x -= lowbit(x);
}
return sum;
} void add(int x,int value){
while(x<=n){
c[x] += value;
x += lowbit(x);
}
} struct node{
int l,r,id;
bool operator < (const node &cmp) const {
return r < cmp.r;
}
}q[Max]; int main()
{
scanf("%d",&n);
memset(mp,-,sizeof(mp));
for(int i = ; i <= n;i ++) scanf("%d",&a[i]);
scanf("%d",&m);
for(int i = ;i <= m;i ++){
scanf("%d%d",&q[i].l,&q[i].r);
q[i].id = i;
}
sort(q+,q+m+);
int l = ;
for(int i = ;i <= m;i ++){
for(int j = l;j <= q[i].r;j ++){
if(mp[a[j]]!=-){
add(mp[a[j]],-);
}
add(j,);
mp[a[j]] = j;
}
l = q[i].r + ;
ans[q[i].id] = getsum(q[i].r) - getsum(q[i].l-);
} for(int i = ;i <= m;i ++){
printf("%d\n",ans[i]);
}
return ;
}

ps:

离线+树状数组耗时为:150ms

很明显这道题使用离线+树状数组的耗时比主席树和莫队要少很多。。且代码量也比较少;

SPOJ DQUERY - D-query (莫队算法|主席树|离线树状数组)的更多相关文章

  1. D-query SPOJ - DQUERY(模板莫队)

    题意: 给定一个序列,询问m次,每次求出区间 [ L,R ] 有多少个不同数字. 套模板就好了...但我不大明白....我的写法为什么不行...唉... #include <iostream&g ...

  2. 【魔改】莫队算法+组合数公式 杭电多校赛4 Problem B. Harvest of Apples

    http://acm.hdu.edu.cn/showproblem.php?pid=6333 莫队算法是一个离线区间分块瞎搞算法,只要满足:1.离线  2.可以O(1)从区间(L,R)更新到(L±1, ...

  3. BZOJ 1878 [SDOI2009]HH的项链 (主席树 或 莫队算法)

    题目链接  HH的项链 这道题可以直接上主席树的模板 #include <bits/stdc++.h> using namespace std; #define rep(i, a, b) ...

  4. 莫队算法学习笔记【BZOJ2038:小Z的袜子】【SPOJ3267:D-query】

    很久以前傻乎乎地看来源奇怪的资料的时候被各种曼哈顿弄晕了. 然后现在学会的是分块方法.另新创一个分块方法. 让我们考虑这样一个区间询问问题…… 它有如下的性质: 0,n个数,Q个询问. 1,它没有修改 ...

  5. 「日常训练&知识学习」莫队算法(二):树上莫队(Count on a tree II,SPOJ COT2)

    题意与分析 题意是这样的,给定一颗节点有权值的树,然后给若干个询问,每次询问让你找出一条链上有多少个不同权值. 写这题之前要参看我的三个blog:Codeforces Round #326 Div. ...

  6. SPOJ COT2 Count on a tree II 树上莫队算法

    题意: 给出一棵\(n(n \leq 4 \times 10^4)\)个节点的树,每个节点上有个权值,和\(m(m \leq 10^5)\)个询问. 每次询问路径\(u \to v\)上有多少个权值不 ...

  7. HDU 6278 - Just h-index - [莫队算法+树状数组+二分][2018JSCPC江苏省赛C题]

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6278 Time Limit: 6000/3000 MS (Java/Others) Memory Li ...

  8. C++ 莫队算法(转)

    胡小兔的良心莫队教程:莫队.带修改莫队.树上莫队   在开始学习莫队之前,照例先甩一道例题:BZOJ 1878 HH的项链. 题意:求区间内数的个数,相同的数只算一次. 在我关于这道题的上一篇题解中, ...

  9. Codeforces617 E . XOR and Favorite Number(莫队算法)

    XOR and Favorite Number time limit per test: 4 seconds memory limit per test: 256 megabytes input: s ...

随机推荐

  1. P2157 [SDOI2009]学校食堂Dining

    题目描述 小F 的学校在城市的一个偏僻角落,所有学生都只好在学校吃饭.学校有一个食堂,虽然简陋,但食堂大厨总能做出让同学们满意的菜肴.当然,不同的人口味也不一定相同,但每个人的口味都可以用一个非负整数 ...

  2. mysql,int(5)、int(10)啥区别联系

    实际没啥区别..这个5和10并不是最大5位,最大10位的意思. 好比选择了int(5),并且当你选择了0填充的话.你的数据假设存了123,那么你的显示会是00123,(有些操作mysql的工具看不出来 ...

  3. Web安全基础实践

    Web安全基础实践 标签(空格分隔): <> 目录 基础问题回答 WebGoat下载安装 SQL注入攻击 - SQL字符串注入(String SQL Injection) - 数字型SQL ...

  4. Android开发——进程间通信之Messenger

    0.  前言 不论是Android还是其他操作系统,都会有自己的IPC机制,所谓IPC(Inter-Process Communication)即进程间通信.首先线程和进程是很不同的概念,线程是CPU ...

  5. python3 简单进度条代码

    进度条代码函数实现 import sys, time class ShowProcess(object): """ 显示处理进度的类 调用该类相关函数即可实现处理进度的显 ...

  6. python中的and和or用法

    在python中and和or返回的值并不是True和false这么简单.虽然他们看上去和c++中的&&和||有些相似.在了解and和or之前,我们先要了解python中的True和Fa ...

  7. Security3: 架构和权限

    架构(Schema)是数据库对象(比如,Table,View,存储过程等)的容器,授予用户对Schema访问的权限,就是授予用户对Schema下所有object的访问权限. 一,架构(Schema)是 ...

  8. SSIS 剖析数据流之:连接和查找转换

    在SSIS的数据流组件中,SSIS引擎使用Merge Join组件和 Lookup组件实现TSQL语句中的inner join 和 outer join 功能,Lookup查找组件的功能更类似TSQL ...

  9. REST-framework快速构建API--四部曲

    代码目录结构: 一.使用原生APIView 使用rest-framework原生的APIView实现过程: 以url(r'^books/$', views.BookView.as_view(),nam ...

  10. 简单模拟flume

    NetCat方式: 远程访问的方式进行消息传递 配置一个Agent,主要配置三个组件: source, channel, sink 上图中为什么channel会带s,变成channels? 可以绑定多 ...