题意可见:https://www.luogu.com.cn/problem/SP3267

可在vj上提交:https://vjudge.net/problem/SPOJ-DQUERY

题意翻译

给出一个长度为n 的数列,a1,a2,a3,,,an ,有q 个询问,每个询问给出数对(i,j),需要你给出ai,ai+1,ai+2...aj这一段中有多少不同的数字

输入输出样例

输入 #1复制

  1. 5
  2. 1 1 2 1 3
  3. 3
  4. 1 5
  5. 2 4
  6. 3 5
输出 #1复制

  1. 3
  2. 2
  3. 3

题解(推荐莫队讲解博客:https://www.cnblogs.com/WAMonster/p/10118934.html):

我们可以用左指针和右指针在[1,n]这个区间上移动。题目给了q个询问区间,如果左指针和右指针和某个询问区间的左右边界对应,那就记录一下这个区间对应的结果。最后把所有结果都一起输出

因为询问区间的左右边界可能或大或小,那么我们的左右指针就会来回移动,这样很耗时间,我们可以先对n个数分块,然后对所有询问区间排序一下

  1. int cmp(Node a,Node b)
  2. {
  3. //正常是这样写
  4. //return belong[a.l] == belong[b.l] ? a.r < b.r : belong[a.l] < belong[b.l];
  5. //下面这样写的话可以优化时间,主要原理便是右指针跳完奇数块往回跳时在同一个方向能顺路把偶数块跳完,
  6. //然后跳完这个偶数块又能顺带把下一个奇数块跳完。理论上主算法运行时间减半
  7. return (belong[a.l] ^ belong[b.l]) ? belong[a.l] < belong[b.l] : ((belong[a.l] & 1) ? a.r < b.r : a.r > b.r);
  8. }

1、在指针移动过程中枚举到一个数值num,增加出现次数时判断一下cntnum是否为0,如果为0,则这个数值之前没有出现过,现在出现了,数值数当然要+1。反之在从区间中删除num后也判断一下cntnum是否为0,如果为0数值总数-1。

2、其次就是左右指针怎么移动了。假设这个序列是这样子的:(其中Q1Q1、Q2Q2是询问区间)

 

最初左指针在0位置,右指针在1位置,然后排序之后Q1区间肯定在前,所以我们肯定是先把左右指针移动到Q1区间的左右边界位置(下面是用L表示左指针,R表示右指针)

我们发现 l 已经是第一个查询区间的左端点,无需移动。现在我们将 r 右移一位,发现新数值1:

r 继续右移,发现新数值2:

继续右移,发现新数值4:

当 r 再次右移时,发现此时的新位置中的数值2出现过,数值总数不增:

接下来是两个7,由于7没出现过,所以总数+1:

继续右移发现3:

继续右移,但接下来的两个数值都出现过,总数不增。

至此,Q1区间所有数值统计完成,结果为5。

现在我们又看一下Q2区间的情况:

首先我们发现, l 指针在Q2区间左端点的左边,我们需要将它右移,同时删除原位置的统计信息。

将l右移一位到位置2,删除位置1处的数值1。但由于操作后的区间中仍然有数值1存在,所以总数不减。

接下来的两位也是如此,直接删掉即可,总数不减。

当 l 指针继续右移时,发现一个问题:原位置上的数值是2,但是删除这个2后,此时的区间[l,r]中再也没有2了(回顾之前的内容,这种情况就是删除后cnt2=0),那么总数就要-1,因为有一个数值已经不在该区间内出现了,而本题需要统计的就是区间内的数值个数。此步骤如下图:

再右移一位,发现无需减总数,而且ll已经移到了Q2区间的左端点,无需继续移下去(如下图)。当然 r 还是要移动的,只不过没图了,我相信大家应该知道做法的qwq。

r的最后位置:

至于删除操作,也是一样的做法,只不过要先删除当前位置的数值,才能移动指针。

代码:

  1. for(int i=1;i<=m;++i) //m就是排序之后的m个区间
  2. {
  3. int start=node[i].l,last=node[i].r;
  4. while(l<start) now-=!--cnt[arr[l++]];
  5. while(l>start) now+=!cnt[arr[--l]]++;
  6. while(r<last) now+=!cnt[arr[++r]]++;
  7. while(r>last) now-=!--cnt[arr[r--]];
  8. ans[node[i].id]=now;
  9. }

总的复杂度就是:n*√n

代码:

  1. #include <map>
  2. #include <set>
  3. #include <list>
  4. #include <queue>
  5. #include <deque>
  6. #include <cmath>
  7. #include <stack>
  8. #include <vector>
  9. #include <bitset>
  10. #include <cstdio>
  11. #include <string>
  12. #include <cstdlib>
  13. #include <cstring>
  14. #include <iostream>
  15. #include <algorithm>
  16. using namespace std;
  17. const int maxn = 1e6+10;
  18. const int INF = 0x3f3f3f3f;
  19. const double PI = 3.1415926;
  20. const long long N = 1000006;
  21. const double eps = 1e-10;
  22. typedef long long ll;
  23. #define mem(A, B) memset(A, B, sizeof(A))
  24. #define lson rt<<1 , L, mid
  25. #define rson rt<<1|1 , mid + 1, R
  26. #define ls rt<<1
  27. #define rs rt<<1|1
  28. #define SIS std::ios::sync_with_stdiget_mod_new(z-x)o(false), cin.tie(0), cout.tie(0)
  29. #define pll pair<long long, long long>
  30. #define lowbit(abcd) (abcd & (-abcd))
  31. #define max(a, b) ((a > b) ? (a) : (b))
  32. #define min(a, b) ((a < b) ? (a) : (b))
  33. int arr[maxn],cnt[maxn],belong[maxn];
  34. int n,m,sizes,new_size,now,ans[maxn];
  35. struct Node{
  36. int l,r,id;
  37. }node[maxn];
  38. int cmp(Node a,Node b)
  39. {
  40. //正常是这样写
  41. //return belong[a.l] == belong[b.l] ? a.r < b.r : belong[a.l] < belong[b.l];
  42. //下面这样写的话可以优化时间,主要原理便是右指针跳完奇数块往回跳时在同一个方向能顺路把偶数块跳完,
  43. //然后跳完这个偶数块又能顺带把下一个奇数块跳完。理论上主算法运行时间减半
  44. return (belong[a.l] ^ belong[b.l]) ? belong[a.l] < belong[b.l] : ((belong[a.l] & 1) ? a.r < b.r : a.r > b.r);
  45. }
  46. int main()
  47. {
  48. //printf("%d\n",(int)ceil(5.0));
  49. scanf("%d",&n);
  50. sizes=sqrt(n);
  51. new_size=ceil((double)n/sizes);
  52. for(int i=1;i<=new_size;++i)
  53. {
  54. for(int j=(i-1)*sizes+1;j<=i*sizes;++j)
  55. {
  56. belong[j]=i;
  57. }
  58. }
  59. for(int i=1;i<=n;++i)
  60. {
  61. scanf("%d",&arr[i]);
  62. }
  63. scanf("%d",&m);
  64. for(int i=1;i<=m;++i)
  65. {
  66. scanf("%d%d",&node[i].l,&node[i].r);
  67. node[i].id=i;
  68. }
  69. sort(node+1,node+1+m,cmp);
  70. int l=1,r=0,now=0;
  71. for(int i=1;i<=m;++i)
  72. {
  73. int start=node[i].l,last=node[i].r;
  74. while(l<start) now-=!--cnt[arr[l++]];
  75. while(l>start) now+=!cnt[arr[--l]]++;
  76. while(r<last) now+=!cnt[arr[++r]]++;
  77. while(r>last) now-=!--cnt[arr[r--]];
  78. ans[node[i].id]=now;
  79. }
  80. for(int i=1;i<=m;++i) printf("%d\n",ans[i]);
  81. return 0;
  82. }

卡常:

1、#pragma GCC optimize(2)

可以用实践证明,开了O2的莫队简直跑得飞快,连1e6都能无压力跑过,甚至可以比不开O2的版本快上4~5倍乃至更多。然而部分OI比赛中O2是禁止的,如果不禁O2的话,那还是开着吧qwq

实在不行,就optimize(3)(逃

SP3267 DQUERY - D-query 莫队板子题的更多相关文章

  1. E. XOR and Favorite Number (莫队板子题)

    题目链接 #include <bits/stdc++.h> using namespace std; typedef long long ll; inline int read() { , ...

  2. CODEFORCES 340 XOR and Favorite Number 莫队模板题

    原来我直接学的是假的莫队 原题: Bob has a favorite number k and ai of length n. Now he asks you to answer m queries ...

  3. [2009国家集训队]小Z的袜子(hose)(BZOJ2038+莫队入门题)

    题目链接:https://www.lydsy.com/JudgeOnline/problem.php?id=2038 题目: 题意:中文题意,大家都懂. 思路:莫队入门题.不过由于要去概率,所以我们假 ...

  4. 清橙A1206.小Z的袜子 && CF 86D(莫队两题)

    清橙A1206.小Z的袜子 && CF 86D(莫队两题) 在网上看了一些别人写的关于莫队算法的介绍,我认为,莫队与其说是一种算法,不如说是一种思想,他通过先分块再排序来优化离线查询问 ...

  5. wa自动机 的 莫队 刷题记录

    洛谷P2709小B的询问 莫队裸题,模板题 莫队就是把询问区间排个序,先按左端点的Pos排序(POS是分块那个数组),pos一样的按右端点排序 代码: #include <bits/stdc++ ...

  6. 【洛谷2709】小B的询问(莫队模板题)

    点此看题面 大致题意: 有一个长度为\(N\)的序列,每个数字在\(1\sim K\)之间,有\(M\)个询问,每个询问给你一个区间,让你求出\(\sum_{i=1}^K c(i)^2\),其中\(c ...

  7. [SDOI2009][bzoj1878] HH的项链 [莫队模板题]

    题面: 传送门 思路: 就是一道莫队的模板题目...... 开一个1000000的数组记录每个数出现的次数,然后每次从1到0或者从0到1更新答案 莫队讲解看这里:莫队 Code: #include&l ...

  8. (原创)BZOJ 2038 小Z的袜子(hose) 莫队入门题+分块

    I - 小Z的袜子(hose) 作为一个生活散漫的人,小Z每天早上都要耗费很久从一堆五颜六色的袜子中找出一双来穿.终于有一天,小Z再也无法忍受这恼人的找袜子过程,于是他决定听天由命…… 具体来说,小Z ...

  9. [SP3267]DQUERY - D query

    题目传送门 维护一个区间内不同数的个数,最直观的想法是直接排序后用树状数组维护即可.但是我们发现n只有3e4,于是我们想到了可以拿一个$O(n\sqrt{n})$的莫队维护.关于莫队算法如果有不知道的 ...

随机推荐

  1. Linux 用户操作之用户管理 (用户增删改操作)

    目录 添加用户 删除用户 修改用户 切换用户 配置用户密码 查看配置文件 cat /etc/pwsswd 添加用户 可选项 -c comment 指定一段注释性描述. -d 目录 指定用户主目录,如果 ...

  2. 【Vue】Vue框架常用知识点 Vue的模板语法、计算属性与侦听器、条件渲染、列表渲染、Class与Style绑定介绍与基本的用法

    Vue框架常用知识点 文章目录 Vue框架常用知识点 知识点解释 第一个vue应用 模板语法 计算属性与侦听器 条件渲染.列表渲染.Class与Style绑定 知识点解释 vue框架知识体系 [1]基 ...

  3. 惠普电脑(HP PHILIPS系列)安装ubuntu后无法连接WIFI解决方案(手动安装8821CE驱动)

    一步一步来, 先说环境: 我的电脑是HP PHILIPS系列,ubuntu版本是16.04 背景: win10安装ubuntu后发现无法连接wifi(但win10系统可以连接WIFI),在ubuntu ...

  4. druid discard long time none received connection问题解析

    最新项目中用的druid连接数据库遇到一个困扰很久的问题 1 开始用的druid版本是1.1.22版本,由于业务需求,单个连接需要执行很久,理论上不需要用到自动回收,但为了安全,还是加了自动回收,时间 ...

  5. postman接口测试之复制多个接口或collections到某个子文件夹或collections下

    一.痛点 1.postman只支持复制一个请求,或者一个子文件夹,但是不支持复制多个请求,或者整个collections到某个子文件夹或者某个collections下. 2.网上查了好一会儿,没有一个 ...

  6. python的零碎知识

    1.Python代码操作git 安装 pip3 install gitpython 操作git import os from git.repo import Repo # gitpython def ...

  7. Py层次递进与文件修改大程序,模块,name与file

    层次的递进与返回 #输入quit的时候返回上一阶层,输入exit退出所有的循环 tag=True while tag==True: level1=input('level1:') if level1= ...

  8. 06. struts2中指定struts2处理的请求后缀

    概述 默认情况下我们都是使用.action后缀访问Action. 其实默认后缀是可以通过常量"struts.action.extension"进行修改的. 我们可以配置Struts ...

  9. 用CSS制做一个三角形!

    用CSS制做一个三角形! <style> .outer { width: 0; height: 0; border-left: 10px solid transparent; border ...

  10. Redis 实战 —— 09. 实现任务队列、消息拉取和文件分发

    任务队列 P133 通过将待执行任务的相关信息放入队列里面,并在之后对队列进行处理,可以推迟执行那些耗时对操作,这种将工作交给任务处理器来执行对做法被称为任务队列 (task queue) . P13 ...