SPOJ DQUERY - D-query (莫队算法|主席树|离线树状数组)
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 (莫队算法|主席树|离线树状数组)的更多相关文章
- D-query SPOJ - DQUERY(模板莫队)
题意: 给定一个序列,询问m次,每次求出区间 [ L,R ] 有多少个不同数字. 套模板就好了...但我不大明白....我的写法为什么不行...唉... #include <iostream&g ...
- 【魔改】莫队算法+组合数公式 杭电多校赛4 Problem B. Harvest of Apples
http://acm.hdu.edu.cn/showproblem.php?pid=6333 莫队算法是一个离线区间分块瞎搞算法,只要满足:1.离线 2.可以O(1)从区间(L,R)更新到(L±1, ...
- BZOJ 1878 [SDOI2009]HH的项链 (主席树 或 莫队算法)
题目链接 HH的项链 这道题可以直接上主席树的模板 #include <bits/stdc++.h> using namespace std; #define rep(i, a, b) ...
- 莫队算法学习笔记【BZOJ2038:小Z的袜子】【SPOJ3267:D-query】
很久以前傻乎乎地看来源奇怪的资料的时候被各种曼哈顿弄晕了. 然后现在学会的是分块方法.另新创一个分块方法. 让我们考虑这样一个区间询问问题…… 它有如下的性质: 0,n个数,Q个询问. 1,它没有修改 ...
- 「日常训练&知识学习」莫队算法(二):树上莫队(Count on a tree II,SPOJ COT2)
题意与分析 题意是这样的,给定一颗节点有权值的树,然后给若干个询问,每次询问让你找出一条链上有多少个不同权值. 写这题之前要参看我的三个blog:Codeforces Round #326 Div. ...
- SPOJ COT2 Count on a tree II 树上莫队算法
题意: 给出一棵\(n(n \leq 4 \times 10^4)\)个节点的树,每个节点上有个权值,和\(m(m \leq 10^5)\)个询问. 每次询问路径\(u \to v\)上有多少个权值不 ...
- 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 ...
- C++ 莫队算法(转)
胡小兔的良心莫队教程:莫队.带修改莫队.树上莫队 在开始学习莫队之前,照例先甩一道例题:BZOJ 1878 HH的项链. 题意:求区间内数的个数,相同的数只算一次. 在我关于这道题的上一篇题解中, ...
- Codeforces617 E . XOR and Favorite Number(莫队算法)
XOR and Favorite Number time limit per test: 4 seconds memory limit per test: 256 megabytes input: s ...
随机推荐
- P2216 [HAOI2007]理想的正方形
题目描述 有一个a*b的整数组成的矩阵,现请你从中找出一个n*n的正方形区域,使得该区域所有数中的最大值和最小值的差最小. 输入输出格式 输入格式: 第一行为3个整数,分别表示a,b,n的值 第二行至 ...
- 模板自定义函数 template function
sqlite3中的日期默认是UTC,当日期字段的默认值是CURRENT_TIMESTAMP时,这个日期和北京时间CST少了8小时. 网上建议说数据库里用UTC,读取数据时再转换为当地时间. web页面 ...
- 解决Ubuntu14.04安装Chrome浏览器打不开的问题
1.安装Chrome浏览器 wget http://www.linuxidc.com/files/repo/google-chrome.list -P /etc/apt/sources.list.d/ ...
- Django Rest Framework源码剖析(八)-----视图与路由
一.简介 django rest framework 给我们带来了很多组件,除了认证.权限.序列化...其中一个重要组件就是视图,一般视图是和路由配合使用,这种方式给我们提供了更灵活的使用方法,对于使 ...
- 定义C#鼠标指针的形状 Cursor
原文:定义C#鼠标指针的形状 Cursor 定义C#指针形状的两种方法. 1.控件属性定义法: 在Windows应用程序中,通过设置控件的Cursor属性可以定义鼠标的显示形状.控件(如Button控 ...
- 【WPF】数据验证
原文:[WPF]数据验证 引言 数据验证在任何用户界面程序中都是不可缺少的一部分.在WPF中,数据验证更是和绑定紧紧联系在一起,下面简单介绍MVVM模式下常用的几种验证方式. 错误信息显示 ...
- TICTOC: Header Only C++ Timer
感觉最近的更新频率略高啊-哈哈- 这次的带来的是一个十分简单便利的C++计时库. 项目地址:https://github.com/miaoerduo/tictoc 欢迎Start和提MR. 项目中有详 ...
- ABPZERO介绍
内容 首先我们创建一个名为"Acme.PhoneBook"的项目. 本文档是指南会同步开发您的项目. 我们建议你在开发之前准备备份下这份初始项目. 因为abpZero是基于abp的 ...
- Asp.net MVC Razor常见问题及解决方法(转载>云中客)
没有经验的童鞋就是这样磕磕碰碰出来的经验. 1,Datatype的错误提示消息无法自定义 这也许是Asp.net MVC的一个Bug.ViewModel中定义了DataType为Date字段: 1 2 ...
- Flume的简单理解
由于没具体研究过画图,以前在公司每天都用Excel,所以很多图画都是画在了Excel上再剪切的,看着可能不太舒服. 先来看一下数据走向: 这样我们就大致了解了flume是干嘛的,在什么位置了. Flu ...