题意

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

题解

这是一道分块模板题。

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

所以需要预处理的有:

  1. cnt[i][j]: i在前j块中出现的次数
  2. mode[i][j]: 第i块到第j块组成的大区间的众数
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <set>
using namespace std;
typedef long long ll;
#define space putchar(' ')
#define enter putchar('\n')
template <class T>
void read(T &x){
char c;
bool op = 0;
while(c = getchar(), c < '0' || c > '9')
if(c == '-') op = 1;
x = c - '0';
while(c = getchar(), c >= '0' && c <= '9')
x = x * 10 + c - '0';
if(op) x = -x;
}
template <class T>
void write(T x){
if(x < 0) x = -x, putchar('-');
if(x >= 10) write(x / 10);
putchar('0' + x % 10);
} const int N = 40005, B = 200;
int n, m, a[N], lst[N], idx, cnt[N][205], tot[N], vis[N], mode[205][205];
#define st(x) (((x) - 1) * B + 1)
#define ed(x) min((x) * B, n)
#define bel(x) (((x) - 1) / B + 1)
//这次代码写得非常丑陋……连个函数都没有……所以下面的代码中我会加一些注释解释代码含义
int main(){
//读入并离散化
read(n), read(m);
for(int i = 1; i <= n; i++)
read(a[i]), lst[i] = a[i];
sort(lst + 1, lst + n + 1);
idx = unique(lst + 1, lst + n + 1) - lst - 1;
//处理cnt[i][j],表示数i(当然是离散化后的新数)在前j块中出现的次数
for(int i = 1; i <= n; i++){
a[i] = lower_bound(lst + 1, lst + idx + 1, a[i]) - lst;
for(int j = bel(i); st(j) <= n; j++)
cnt[a[i]][j]++;
}
//处理mode[i][j],表示第i块到第j块的众数
for(int i = 1, md = 0; st(i) <= n; i++){
memset(tot, 0, sizeof(tot));
for(int j = i, k = st(i); k <= n; k++){
tot[a[k]]++;
if(tot[a[k]] > tot[md] || (tot[a[k]] == tot[md] && a[k] < md)) md = a[k];
if(k == ed(j)) mode[i][j] = md, j++;
}
if(i != 2) continue;
}
//回答询问
int ans = 0;
for(int T = 1; T <= m; T++){
int l, r, md = 0;
read(l), read(r);
l = (l + ans - 1) % n + 1, r = (r + ans - 1) % n + 1;
if(l > r) swap(l, r);
//如果询问的区间在某一个块中
if(bel(l) == bel(r)){
for(int i = l; i <= r; i++){
if(vis[a[i]] != T) tot[a[i]] = 0, vis[a[i]] = T;
tot[a[i]]++;
if(tot[a[i]] > tot[md] || (tot[a[i]] == tot[md] && a[i] < md)) md = a[i];
}
write(ans = lst[md]), enter;
continue;
}
//如果区间跨块,则答案可能是:1. 中间那几个整块表示的大区间的众数;2. 两边零散部分的数
md = mode[bel(l) + 1][bel(r) - 1]; //中间大区间的众数
vis[md] = T, tot[md] = 0;
//这里我一开始忘记了特殊处理md的vis数组,导致计算md出现次数时额外加上了上次询问更新出的tot。
for(int i = l; i <= ed(bel(l)); i++){ //处理左侧零散区间
if(vis[a[i]] != T) tot[a[i]] = 0, vis[a[i]] = T;
tot[a[i]]++;
int x = tot[a[i]] + cnt[a[i]][bel(r) - 1] - cnt[a[i]][bel(l)];
int y = tot[md] + cnt[md][bel(r) - 1] - cnt[md][bel(l)];
if(x > y || (x == y && a[i] < md)) md = a[i];
}
for(int i = st(bel(r)); i <= r; i++){ //处理右侧零散区间
if(vis[a[i]] != T) tot[a[i]] = 0, vis[a[i]] = T;
tot[a[i]]++;
int x = tot[a[i]] + cnt[a[i]][bel(r) - 1] - cnt[a[i]][bel(l)];
int y = tot[md] + cnt[md][bel(r) - 1] - cnt[md][bel(l)];
if(x > y || (x == y && a[i] < md)) md = a[i];
}
write(ans = lst[md]), enter;
}
return 0;
}

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. Jmeter关联处理

    采桑子·重阳 人生易老天难老, 岁岁重阳. 今又重阳, 战地黄花分外香. 一年一度秋风劲, 不似春光. 胜似春光, 廖廓江天万里霜. 当请求之间有依赖关系,比如一个请求的入参是另一个请求返回的数据,这 ...

  2. Linux Ubuntu 安装、汉化、常用操作

    一.安装Ubuntu Desktop 安装前准备 现在的PC机都可以满足要求. 软件准备 vmware:http://www.vmware.com/cn ubuntu:18ubuntu Desktop ...

  3. vue 组件-组件定义的4种方式

    一.组件命名的方式 ①kebab-case,单词之间采用  - (短横线)连接,例如:my-component ,在DOM中使用时,<my-component ></my-compo ...

  4. CHAPTER 40 Science in Our Digital Age 第40章 我们数字时代的科学

    CHAPTER 40 Science in Our Digital Age 第40章 我们数字时代的科学 The next time you switch on your computer, you ...

  5. 重磅发布 | 黑镜调查:深渊背后的真相之「DDoS 威胁与黑灰产业调查报告」

    欢迎大家前往腾讯云+社区,获取更多腾讯海量技术实践干货哦~ 本文由云鼎实验室发表于云+社区专栏 本文经授权转载自 FreeBuf 2018年世界杯硝烟散尽,但关于她的话题却远远没有结束.说起世界杯,就 ...

  6. pycharm连接服务器

    python其他知识目录 1. pycharm当做xshell等远程工具,远程连接服务器步骤: 2.pycharm结合Linux服务器进行代码学习: 2.2使用pycharm远程在服务器上修改和执行代 ...

  7. Python基础系列讲解——继承派生和组合的概念剖析

    Python作为一门面向对象的语言,它的面向对象体系中主要存在这么两种关系,一个是“类”和“实例”的关系,另一个是“父类”和“子类”的关系. 所谓“类”是从一堆对象中以抽象的方式把相同的特征归类得到的 ...

  8. 为什么找程序员一定要看他的 GitHub

    听说 最开始听到这句话是某知名互联网公司大牛告诉我的,我很不以为然,不过迫于他是"leader"我也注册了一个 highsea (广告 0.0):当然我可懒得 push 更别提 c ...

  9. Task 9 从用户界面和体验分析“360极速浏览器”

    我目前使用的浏览器是360极速浏览器,下面将针对用户界面.记住用户选择.短期刺激.长期使用的好处坏处.不要让用户犯简单的错误四个方面对其进行评估: 1.用户界面: 01 可视性原则--网络没有连接或者 ...

  10. 《UML大战需求分析》-读后感三

    用例图是用来描述什么角色通过某某系统能做什么的图,用例图关注的是系统的外在表示想爱你.系统与人的交互系统与其他系统的交互,小人执行者就是角色,角色 是对系统使用者的抽象,一个角色可以代表多个具体的人而 ...