BZOJ 2724 蒲公英 | 分块模板题
题意
给出一个序列,在线询问区间众数。如果众数有多个,输出最小的那个。
题解
这是一道分块模板题。
一个询问的区间的众数,可能是中间“整块”区间的众数,也可能是左右两侧零散的数中的任意一个。为了\(O(\sqrt n)\)求出究竟是哪一个,我们需要在一次对两侧零散点的扫描之后\(O(1)\)求出被扫数在区间内的的出现次数。
所以需要预处理的有:
- cnt[i][j]: i在前j块中出现的次数
- 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 蒲公英 | 分块模板题的更多相关文章
- BZOJ 2724蒲公英 (分块) 【内有块大小证明】
题面 luogu传送门 分析 先分块,设块大小为x(之后我们会证明块大小取何值会更优) 步骤1 把所有的数离散化,然后对每个值开一个vector pos[i],pos[i]存储数i出现的位置 我们设查 ...
- bzoj 2724 蒲公英 分块
分块,预处理出每两个块范围内的众数,然后在暴力枚举块外的进行比较 那么怎么知道每一个数出现的次数呢?离散后,对于每一个数,维护一个动态数组就好了 #include<cstdio> #inc ...
- Luogu 2801 教主的魔法 | 分块模板题
Luogu 2801 教主的魔法 | 分块模板题 我犯的错误: 有一处l打成了1,还看不出来-- 缩小块大小De完bug后忘了把块大小改回去就提交--还以为自己一定能A了-- #include < ...
- 卿学姐与公主 UESTC - 1324 分块模板题
题意:http://acm.uestc.edu.cn/#/problem/show/1324 中文题,自己看喽. 题解:分块模板,update时顺便更新块属性.ask时先判掉belong[l]==be ...
- BZOJ 1180 / 2843 LCT模板题_双倍经验
一大早上到机房想先拍一下模板,热热身. 结果....对照着染色敲的 LCT 竟然死活也调不过去(你说我抄都能抄错) 干脆自己重新敲了一遍,10min就敲完了....... 还是要相信自己 Code: ...
- BZOJ 2982: combination Lucas模板题
Code: #include<bits/stdc++.h> #define ll long long #define maxn 1000003 using namespace std; c ...
- [BZOJ 2724] [Violet 6] 蒲公英 【分块】
题目链接:BZOJ - 2724 题目分析 这道题和 BZOJ-2821 作诗 那道题几乎是一样的,就是直接分块,每块大小 sqrt(n) ,然后将数字按照数值为第一关键字,位置为第二关键字排序,方便 ...
- BZOJ 2724: [Violet 6]蒲公英 [分块 区间众数]
传送门 题面太美不忍不放 分块分块 这种题的一个特点是只有查询,通常需要预处理:加入修改的话需要暴力重构预处理 预处理$f[i][j]$为第i块到第j块的众数,显然$f[i][j]=max{f[i][ ...
- 【BZOJ 1507】【NOI 2003】&【Tyvj P2388】Editor 块状链表模板题
2016-06-18 当时关于块状链表的想法是错误的,之前维护的是一个动态的$\sqrt{n}$,所以常数巨大,今天才知道原因TwT,请不要参照这个程序为模板!!! 模板题水啊水~~~ 第一次写块状链 ...
随机推荐
- 【CodeForces-1041C】Coffee Break(二分解决关于set,pair,upper_bound用法)
//题意:一个的工作时间是m分钟. // 在特定的时间和咖啡 n a1,a2....an,, ai代表的是每个咖啡要在一天中对应的时间点喝掉 // 每一次喝咖啡的时间为1分钟 // 必须在一天中的ai ...
- maven scope属性值设置含义
1.枚举各个属性值的含义 compile,缺省值,适用于所有阶段,会打包进项目. provided,类似compile,期望JDK.容器或使用者会提供这个依赖. runtime,只在运行时使用,如JD ...
- MapReduce任务学习系列
首先放一张官方图片,大致了解下整个MapReduce的处理过程. 抛出如下疑问: 1.MapReduce的基本原理是什么?即利用什么机制来实现的任务拆分处理? 2.MapReduce任务执行过程是什么 ...
- Redis源码阅读(一)事件机制
Redis源码阅读(一)事件机制 Redis作为一款NoSQL非关系内存数据库,具有很高的读写性能,且原生支持的数据类型丰富,被广泛的作为缓存.分布式数据库.消息队列等应用.此外Redis还有许多高可 ...
- 基于openvswitch+Docker构建SDN网络测试环境 (使用ovs-docker进行构建)
这是一篇之前写的笔记,主要记录了使用openvswitch + Docker 等进行一个小型的SDN网络搭建的操作步骤.由于 之前临时有其他任务,耽搁了一下,最近开始重新整理,并计划开发一个简单的Py ...
- 基于C#的机器学习--惩罚与奖励-强化学习
强化学习概况 正如在前面所提到的,强化学习是指一种计算机以“试错”的方式进行学习,通过与环境进行交互获得的奖赏指导行为,目标是使程序获得最大的奖赏,强化学习不同于连督学习,区别主要表现在强化信号上,强 ...
- windows docker 安装cloudera/quickstart
最近需要写一个大数据的项目,但是公司没有测试环境,真是cao蛋,没办法,只能自己搭建一个测试环境,所以就在本地电脑装一个cloudera/quickstart,这个是一个单节点的大数据平台, 是clo ...
- nginx keepalived 高可用方案(转)
转自: https://www.cnblogs.com/leeSmall/p/9356535.html 一.Nginx Rewrite 规则 1. Nginx rewrite规则 Rewrite规则含 ...
- 函数式编程与React高阶组件
相信不少看过一些框架或者是类库的人都有印象,一个函数叫什么creator或者是什么什么createToFuntion,总是接收一个函数,来返回另一个函数.这是一个高阶函数,它可以接收函数可以当参数,也 ...
- 迎来OO的曙光,总结规格的意义——OO第四次博客总结
一切都要结束了,砥砺前行~ 一.测试与正确性论证的效果差异 测试,顾名思义就是我们暴力用大量数据轰炸编写的程序的过程.日常的OO过程中,我们经常互相寻求“测试集”,正是因为测试使用特定数据对我们的功能 ...