题意

给出一个序列,在线询问区间众数。如果众数有多个,输出最小的那个。

题解

这是一道分块模板题。

一个询问的区间的众数,可能是中间“整块”区间的众数,也可能是左右两侧零散的数中的任意一个。为了\(O(\sqrt n)\)求出究竟是哪一个,我们需要在一次对两侧零散点的扫描之后\(O(1)\)求出被扫数在区间内的的出现次数。

所以需要预处理的有:

  1. cnt[i][j]: i在前j块中出现的次数
  2. mode[i][j]: 第i块到第j块组成的大区间的众数
  1. #include <cstdio>
  2. #include <cstring>
  3. #include <algorithm>
  4. #include <set>
  5. using namespace std;
  6. typedef long long ll;
  7. #define space putchar(' ')
  8. #define enter putchar('\n')
  9. template <class T>
  10. void read(T &x){
  11. char c;
  12. bool op = 0;
  13. while(c = getchar(), c < '0' || c > '9')
  14. if(c == '-') op = 1;
  15. x = c - '0';
  16. while(c = getchar(), c >= '0' && c <= '9')
  17. x = x * 10 + c - '0';
  18. if(op) x = -x;
  19. }
  20. template <class T>
  21. void write(T x){
  22. if(x < 0) x = -x, putchar('-');
  23. if(x >= 10) write(x / 10);
  24. putchar('0' + x % 10);
  25. }
  26. const int N = 40005, B = 200;
  27. int n, m, a[N], lst[N], idx, cnt[N][205], tot[N], vis[N], mode[205][205];
  28. #define st(x) (((x) - 1) * B + 1)
  29. #define ed(x) min((x) * B, n)
  30. #define bel(x) (((x) - 1) / B + 1)
  31. //这次代码写得非常丑陋……连个函数都没有……所以下面的代码中我会加一些注释解释代码含义
  32. int main(){
  33. //读入并离散化
  34. read(n), read(m);
  35. for(int i = 1; i <= n; i++)
  36. read(a[i]), lst[i] = a[i];
  37. sort(lst + 1, lst + n + 1);
  38. idx = unique(lst + 1, lst + n + 1) - lst - 1;
  39. //处理cnt[i][j],表示数i(当然是离散化后的新数)在前j块中出现的次数
  40. for(int i = 1; i <= n; i++){
  41. a[i] = lower_bound(lst + 1, lst + idx + 1, a[i]) - lst;
  42. for(int j = bel(i); st(j) <= n; j++)
  43. cnt[a[i]][j]++;
  44. }
  45. //处理mode[i][j],表示第i块到第j块的众数
  46. for(int i = 1, md = 0; st(i) <= n; i++){
  47. memset(tot, 0, sizeof(tot));
  48. for(int j = i, k = st(i); k <= n; k++){
  49. tot[a[k]]++;
  50. if(tot[a[k]] > tot[md] || (tot[a[k]] == tot[md] && a[k] < md)) md = a[k];
  51. if(k == ed(j)) mode[i][j] = md, j++;
  52. }
  53. if(i != 2) continue;
  54. }
  55. //回答询问
  56. int ans = 0;
  57. for(int T = 1; T <= m; T++){
  58. int l, r, md = 0;
  59. read(l), read(r);
  60. l = (l + ans - 1) % n + 1, r = (r + ans - 1) % n + 1;
  61. if(l > r) swap(l, r);
  62. //如果询问的区间在某一个块中
  63. if(bel(l) == bel(r)){
  64. for(int i = l; i <= r; i++){
  65. if(vis[a[i]] != T) tot[a[i]] = 0, vis[a[i]] = T;
  66. tot[a[i]]++;
  67. if(tot[a[i]] > tot[md] || (tot[a[i]] == tot[md] && a[i] < md)) md = a[i];
  68. }
  69. write(ans = lst[md]), enter;
  70. continue;
  71. }
  72. //如果区间跨块,则答案可能是:1. 中间那几个整块表示的大区间的众数;2. 两边零散部分的数
  73. md = mode[bel(l) + 1][bel(r) - 1]; //中间大区间的众数
  74. vis[md] = T, tot[md] = 0;
  75. //这里我一开始忘记了特殊处理md的vis数组,导致计算md出现次数时额外加上了上次询问更新出的tot。
  76. for(int i = l; i <= ed(bel(l)); i++){ //处理左侧零散区间
  77. if(vis[a[i]] != T) tot[a[i]] = 0, vis[a[i]] = T;
  78. tot[a[i]]++;
  79. int x = tot[a[i]] + cnt[a[i]][bel(r) - 1] - cnt[a[i]][bel(l)];
  80. int y = tot[md] + cnt[md][bel(r) - 1] - cnt[md][bel(l)];
  81. if(x > y || (x == y && a[i] < md)) md = a[i];
  82. }
  83. for(int i = st(bel(r)); i <= r; i++){ //处理右侧零散区间
  84. if(vis[a[i]] != T) tot[a[i]] = 0, vis[a[i]] = T;
  85. tot[a[i]]++;
  86. int x = tot[a[i]] + cnt[a[i]][bel(r) - 1] - cnt[a[i]][bel(l)];
  87. int y = tot[md] + cnt[md][bel(r) - 1] - cnt[md][bel(l)];
  88. if(x > y || (x == y && a[i] < md)) md = a[i];
  89. }
  90. write(ans = lst[md]), enter;
  91. }
  92. return 0;
  93. }

BZOJ 2724 蒲公英 | 分块模板题的更多相关文章

  1. BZOJ 2724蒲公英 (分块) 【内有块大小证明】

    题面 luogu传送门 分析 先分块,设块大小为x(之后我们会证明块大小取何值会更优) 步骤1 把所有的数离散化,然后对每个值开一个vector pos[i],pos[i]存储数i出现的位置 我们设查 ...

  2. bzoj 2724 蒲公英 分块

    分块,预处理出每两个块范围内的众数,然后在暴力枚举块外的进行比较 那么怎么知道每一个数出现的次数呢?离散后,对于每一个数,维护一个动态数组就好了 #include<cstdio> #inc ...

  3. Luogu 2801 教主的魔法 | 分块模板题

    Luogu 2801 教主的魔法 | 分块模板题 我犯的错误: 有一处l打成了1,还看不出来-- 缩小块大小De完bug后忘了把块大小改回去就提交--还以为自己一定能A了-- #include < ...

  4. 卿学姐与公主 UESTC - 1324 分块模板题

    题意:http://acm.uestc.edu.cn/#/problem/show/1324 中文题,自己看喽. 题解:分块模板,update时顺便更新块属性.ask时先判掉belong[l]==be ...

  5. BZOJ 1180 / 2843 LCT模板题_双倍经验

    一大早上到机房想先拍一下模板,热热身. 结果....对照着染色敲的 LCT 竟然死活也调不过去(你说我抄都能抄错) 干脆自己重新敲了一遍,10min就敲完了....... 还是要相信自己 Code: ...

  6. BZOJ 2982: combination Lucas模板题

    Code: #include<bits/stdc++.h> #define ll long long #define maxn 1000003 using namespace std; c ...

  7. [BZOJ 2724] [Violet 6] 蒲公英 【分块】

    题目链接:BZOJ - 2724 题目分析 这道题和 BZOJ-2821 作诗 那道题几乎是一样的,就是直接分块,每块大小 sqrt(n) ,然后将数字按照数值为第一关键字,位置为第二关键字排序,方便 ...

  8. BZOJ 2724: [Violet 6]蒲公英 [分块 区间众数]

    传送门 题面太美不忍不放 分块分块 这种题的一个特点是只有查询,通常需要预处理:加入修改的话需要暴力重构预处理 预处理$f[i][j]$为第i块到第j块的众数,显然$f[i][j]=max{f[i][ ...

  9. 【BZOJ 1507】【NOI 2003】&【Tyvj P2388】Editor 块状链表模板题

    2016-06-18 当时关于块状链表的想法是错误的,之前维护的是一个动态的$\sqrt{n}$,所以常数巨大,今天才知道原因TwT,请不要参照这个程序为模板!!! 模板题水啊水~~~ 第一次写块状链 ...

随机推荐

  1. PSO算法的改进(参数)

    ## 基本PSO的改进 虽然粒子群在求解优化函数时,表现了较好的寻优能力:通过迭代寻优计算,能够迅速找到近似解:但基本的PSO容易陷入局部最优,导致结果误差较大. 两个方面:1.将各种先进理论引入到P ...

  2. linux下实现压测-html报表生成-控制台参数优化【jmeter】

    jmeter - 单机压测 - 命令行模式-html报表生成-控制台参数优化 一/ 准备工作 1.压力机安装并配置好 jdk 2.调试好程序脚本 再上传到 linux下 3.进入jmeter  bin ...

  3. 学习笔记 | Github

    Github教程 \(Github\)是个好东西QwQ 存代码不用U盘爸爸妈妈再也不用担心我的U盘弄丢没有备份啦! 创建github账号 创建仓库 输入命令 git clone https://git ...

  4. 进阶:2.GBDT算法梳理

    GBDT算法梳理 学习内容: 1.前向分布算法 2.负梯度拟合 3.损失函数 4.回归 5.二分类,多分类 6.正则化 7.优缺点 8.sklearn参数 9.应用场景 1.前向分布算法 在学习模型时 ...

  5. XSS构造技巧

    利用字符编码: 百度曾经出过一个XSS漏洞,在一个<script>标签中输出一个变量,其中转义了双引号: var redirectUrl="\";alert(/XSS/ ...

  6. map的运用

    一.map是一种关联容器,支持高效的查找和访问 map中的元素是一些关键字-值(key-value)对: 关键字起索引作用: 值表示与索引相关联的数据. 关联容器中元素是根据关键字存储的,故其不支持位 ...

  7. string类型的常用方法

    1. 在尾部插入/删除元素 string s("hello"); // 插入/删除一个字符 s.push_back('!'); s.pop_back(); // 插入多个字符 s. ...

  8. 信息安全系统设计基础_exp1

    北京电子科技学院(BESTI) 实     验    报     告 课程:信息安全系统设计基础 班级:1353 姓名:吴子怡.郑伟 学号:20135313.20135322 指导教师: 娄嘉鹏 实验 ...

  9. Task 10 统计从1到某个整数之间出现的1的次数

    任务:给定一个十进制的正整数,写下从1开始,到N的所有整数,然后数一下其中出现“1”的个数. 要求: 写一个函数 f(N) ,返回1 到 N 之间出现的 “1”的个数.例如 f(12) = 5. 在3 ...

  10. 使用Axure RP设计Android界面原型

    转至@徐州瑞步科技(http://www.cnblogs.com/brooks-dotnet/archive/2013/06/05/3119923.html) 资源地址:http://pan.baid ...