English Vietnamese
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
好久之前就做了这个题目了,但是一直没有写篇博客,也是因为一直不太理解吧。
查询区间有多少种数,查询次数 和 数列长度 都很大。一开始想有没有前缀和的关系,大失所望,没有。。例如 1 2 2 1 3 1位置和4位置都有1 1 到 3 有 2 种数 1 到 5 有 3 种数 ,那相减就是 4 到 5 有1种数 答案显然是2种数 因为 前面的区间和后面的区间有相同的数 ,这样相减就会忽略后面的数。所以我们要对 m 次查询进行离线化 ,按右边界r从小到大进行排序 然后数列中相同的数只保留最后一次出现的位置 ,之前出现过的位置的c值就要-1。这样就不用遍历n*q遍了。
代码如下:

#include<bits/stdc++.h>
#define ll long long
using namespace std;const int maxx=2e5+100;
struct node{int id;int l;int r;bool operator <(const node &a)const{return a.r>r;}
}p[maxx];
map<int,int>mp;
int a[maxx],c[maxx],ans[maxx];
int n,m;inline void init()
{mp.clear();memset(c,0,sizeof(c));
}
inline int lowbit(int x){return x&(-x);}
inline void update(int cur,int v){while(cur<=maxx) c[cur]+=v,cur+=lowbit(cur);}
inline int query(int cur){int sum=0;while(cur>0) sum+=c[cur],cur-=lowbit(cur);return sum;}
int main()
{while(~scanf("%d",&n)){init();for(int i=1;i<=n;i++) scanf("%d",&a[i]);scanf("%d",&m);for(int i=1;i<=m;i++) scanf("%d%d",&p[i].l,&p[i].r),p[i].id=i;sort(p+1,p+1+m);int cnt=1;for(int i=1;i<=m;i++){for(int j=cnt;j<=p[i].r;j++){if(mp[a[j]]) update(mp[a[j]],-1);mp[a[j]]=j;update(j,1);}cnt=p[i].r+1;ans[p[i].id]=query(p[i].r)-query(p[i].l-1);}for(int i=1;i<=m;i++) printf("%d%c",ans[i],'\n');}return 0;
}

这是树状数组||线段树+离线做法。
主席树也可以求区间种类数。因为主席树把之前各个历史版本都能保存下来,这样我们就不用离线做了,就可以直接在线做了。但是还是如果之前出现过了,就在之前的版本减一,在当前版本加一。然后再右端点这个版本求(l,r)的种类数。
代码如下:

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;const int maxn = 30000 + 10;
int n,q;
int cnt = 0;
struct Node{int l,r,sum;
}p[maxn*40];int la[1000000 + 10];
int a[maxn];
int root[maxn];int build(int l,int r){int nc = ++cnt;p[nc].sum = 0;p[nc].l = p[nc].r = 0;if (l == r) return nc;int m = l + r >> 1;p[nc].l = build(l,m);p[nc].r = build(m+1,r);return nc;
}int update(int pos,int c,int v,int l,int r)
{int nc = ++cnt;p[nc] = p[c];p[nc].sum += v;if (l == r) return nc;int m = l+r>>1;if (m >= pos){p[nc].l = update(pos,p[c].l,v,l,m);}else {p[nc].r = update(pos,p[c].r,v,m+1,r);}return nc;
}int query(int pos,int c,int l,int r){if (l == r) return p[c].sum;int m = l + r >> 1;if (m >= pos){return p[p[c].r].sum + query(pos,p[c].l,l,m);}else return query(pos,p[c].r,m+1,r);
}int main()
{scanf("%d",&n);memset(la,-1,sizeof la);for (int i = 1; i <= n; ++i){scanf("%d",a+i);}root[0] = build(1,n);for (int i = 1 ; i <= n; ++i){int v = a[i];if (la[v] == -1){root[i] = update(i,root[i-1],1,1,n);}else{int t = update(la[v],root[i-1],-1,1,n);root[i] = update(i,t,1,1,n);}la[v] = i;}scanf("%d",&q);while(q--){int x,y;scanf("%d %d",&x, &y);printf("%d\n",query(x,root[y],1,n));}return 0;
}

努力加油a啊,(o)/~

D-query SPOJ - DQUERY(求区间不同数的个数)(树状数组||线段树+离散)(主席树+在线)相关推荐

  1. [蓝桥杯][2016年第七届真题]压缩变换(主席树求区间不同数的个数)

    题目描述 小明最近在研究压缩算法. 他知道,压缩的时候如果能够使得数值很小,就能通过熵编码得到较高的压缩比. 然而,要使数值很小是一个挑战. 最近,小明需要压缩一些正整数的序列,这些序列的特点是,后面 ...

  2. szu 寒训第二天 树状数组 二维树状数组详解,以及树状数组扩展应用【求逆序对,以及动态第k小数】

    树状数组(Binary Index Tree) 树状数组可以解决可以转化为前缀和问题的问题 这是一类用以解决动态前缀和的问题 (有点像线段树简版) 1.对于 a1 + a2 + a3 + - + an ...

  3. 51nod 1680区间求和 (dp+树状数组/线段树)

    不妨考虑已知一个区间[l,r]的k=1.k=2....k=r-l+1这些数的答案ans(只是这一个区间,不包含子区间) 那么如果加入一个新的数字a[i](i = r+1) 则新区间[l, i]的答案为 ...

  4. SPOJ DQUERY 求区间内不同数的个数 主席树

    这题跟HDU3333差不多吧. 离线的做法很简单,不再说了 以前做过. 主席树的做法就比较暴力了.. 什么是主席树呢.. 其实是某种称号. 在该题中的体现是可持久化的线段树. 对于一个数 如果以前没出 ...

  5. Galahad(板子:区间不重复数字的和,树状数组/线段树)

    链接:https://ac.nowcoder.com/acm/contest/1084/B 来源:牛客网 Galahad 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 131072K ...

  6. AcWing - 246. 区间最大公约数(树状数组+线段树)

    题目链接:点击查看 题目大意:给出一个长度为 nnn 的序列,需要执行 mmm 次操作,每次操作分为下列两种类型: C l r d:将区间 [l,r][l,r][l,r] 位置的数字都加上 ddd Q ...

  7. zoj 2112 树状数组 套主席树 动态求区间 第k个数

    总算是把动态求区间第k个数的算法看明白了. 在主席树的基础上,如果有修改操作,则要通过套树状数组来实现任意区间求第k小的问题. 刚开始看不明白什么意思,现在有一点理解.树状数组的每个元素是一个线段树, ...

  8. 树状数组 区间update/query

    Re [问题引入] 对于区间修改.区间查询这样的简单问题,打一大堆线段树确实是不划算,今天来介绍一下区间查询+区间修改的树状数组 [一些基础] 树状数组的基本知识不再介绍,请自行百度 我们假设sigm ...

  9. 数据结构一【树状数组】普通、二维、离线树状数组的(单点修改,单点查询,区间修改,区间查询)模板及应用例题总结

    文章目录 树状数组 lowbit 线段树与树状数组 单点修改 区间查询 区间修改 区间求和 二维树状数组 离线树状数组 例题 POJ:stars MooFest [SDOI2009]HH的项链 Tur ...

最新文章

  1. iOS OC和Swift混编
  2. python def函数报错详解_【python】详解python函数定义 def()与参数args、可变参数*args、关键参数**args使用实例...
  3. java json 内部类_使用Fastjson解析内部类的一个小问题
  4. 话里话外:按单制造(MTO II)信息化管理特点
  5. 计算机科学与技术python方向_专业解读丨计算机科学与技术
  6. python编程狮苹果系统_Python编程狮app下载-Python编程狮苹果版v1.0
  7. Bzoj 4408: [Fjoi 2016]神秘数 可持久化线段树,神题
  8. 企业信息化认知的四个误区
  9. matlab 模态,用matlab做模态分析
  10. 解密拼多多800元裂变营销新方法
  11. ubuntu查询显卡型号
  12. linux防火墙设置命令,linux防火墙设置命令是什么
  13. python之pil的使用
  14. NAR:人类虚拟代谢数据库——整理人类和肠道菌群与营养和疾病
  15. js 复制图片到微信
  16. Redis 位图数据结构介绍
  17. 红帽RHCE之DHCP
  18. 基于ssm高校科研管理系统-计算机毕业设计源码+LW文档
  19. 数据库同步非常实用的工具,阿里数据迁移工具yugong使用细则
  20. C# NewtonJson 使用技巧

热门文章

  1. ios15之取消UITabbleViewCell的高亮效果
  2. IOS中的AFNetworking框架的GET参数的使用
  3. XCode的使用心得
  4. AFN框架和SDWebImage框架的上手体验
  5. java手动提交事务_Mybatis是如何将事务和连接池高效的结合的
  6. 74cms3.0——Error:Can‘t select MySQL database(74cms3.0)...
  7. 通过Android studio使用git创建本地分支提交远程仓库以及如何查看切换分支
  8. php中的冒泡排序实例,PHP实现冒泡排序的简单实例,php冒泡排序_PHP教程
  9. 实现一个简单的Tomcat
  10. 风口上的储能,光伏要飞起来?