题面

luogu传送门

分析

先分块,设块大小为x(之后我们会证明块大小取何值会更优)

步骤1

把所有的数离散化,然后对每个值开一个vector pos[i],pos[i]存储数i出现的位置

我们设查询的区间为[l,r],需要求数v出现的次数,然后在vector中二分查找出第一个>=l的数的位置p1,和第一个>r的数的位置p2,p2-p1即为数v出现的次数

例:
离散化后的数组a={1,3,3,2,3,1,3 },则pos[3]={2,3,5,7},因为第2,3,5个数为3 我们需要查找[2,6]中数3出现的次数,发现p1=2,p2=4,出现的次数即为2

步骤2

然后我们考虑询问,如果只记录每个块里的众数显然是不行的,因为我们需要把许多个块的结果合起来,而众数不满足区间可加性,无法在\(O(\sqrt n)\)的时间内完成结果合并

因此我们预处理出所有块端点组成的区间,\(mode[l][r],maxt[l][r]\),表示[第l个块的起点,第r个块的终点]这个区间里的众数和众数的出现次数

查询[l,r]时我们可以得到中间的一个由块端点组成的区间,可以直接通过刚刚的预处理得到众数和众数的出现次数

两边多余的部分直接用步骤1暴力即可

至于mode,maxt数组如何预处理,直接用两重for循环来实现

首先枚举块的起点i,然后j从i遍历到n,用一个临时数组cnt来记录每个数出现的次数,就可以求出区间[i,j]的众数,如果j正好是块端点,则记录答案

for(int i=1; i<=bl; i++) {
int ans=INF;
int tim=0;
for(int j=lb(i); j<=n; j++) {
cnt[a[j]]++;
if(cnt[a[j]]>tim||(cnt[a[j]]==tim&&a[j]<ans)) {
ans=a[j];
tim=cnt[a[j]];
}
if(j%sz==0) {
mode[i][j/sz]=ans;
maxt[i][j/sz]=tim;
}else if(j==n){
mode[i][bl]=ans;
maxt[i][bl]=tim;
}
}
for(int j=lb(i); j<=n; j++) cnt[a[j]]=0;
}

时间复杂度分析

设块的大小为x,假设n为x的倍数

初始化部分:

从第一个块末尾需要遍历n-x次,从第二个块末尾需要遍历n-2x次,从第\(\frac{n}{x}\)个块末尾需要遍历\(n-x·\frac{n}{x}\)次

总的遍历次数为

\[(n-x)+(n-2x)+\dots+n-x·\frac{n}{x}=\frac{n^2}{2x}-\frac{1}{2}n
\]

其中\(\frac{1}{2}n\)可忽略,时间复杂度为\(O(\frac{n^2}{x})\)

查询部分:

考虑查询的极端情况,查询[2,n-1]

则需要遍历左,右长度各为(x-1)的块(可近似看成x)

时间复杂度为\(O(x \log n)\)

m次询问\(O(mx \log n)\)

所以总时间复杂度为\(O(\frac{n^2}{x}+mx \log n)\)

根据均值不等式

当\(x=\sqrt{\frac{n^2}{m \log n}}\)时,总时间复杂度为\(2\sqrt{n^2m\log n}=O(n\sqrt{m\log n})\)

因此块大小为\(\sqrt{\frac{n^2}{m \log n}}\)时最优,由于n,m同级,可近似取\(\sqrt{n \log n}\)

代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<map>
#include<cmath>
#include<vector>
#define maxn 100005
#define maxs 2005
#define INF 0x7fffffff
using namespace std;
inline void qread(int &x) {
x=0;
int sign=1;
char c=getchar();
while(c<'0'||c>'9') {
if(c=='-') sign=-1;
c=getchar();
}
while(c>='0'&&c<='9') {
x=x*10+c-'0';
c=getchar();
}
x=x*sign;
}
inline void qread(long long &x) {
x=0;
long long sign=1;
char c=getchar();
while(c<'0'||c>'9') {
if(c=='-') sign=-1;
c=getchar();
}
while(c>='0'&&c<='9') {
x=x*10+c-'0';
c=getchar();
}
x=x*sign;
}
inline void qprint(int x) {
if(x<0) {
putchar('-');
qprint(-x);
} else if(x==0) {
putchar('0');
return;
} else {
if(x/10>0) qprint(x/10);
putchar('0'+x%10);
}
} int n,m,num,sz,bl;
int id[maxn];//第i个位置属于的块编号
int a[maxn];
int b[maxn];
inline int lb(int id) {//求第id个块的左端点
return sz*(id-1)+1;
}
inline int rb(int id) {//求第id个块的右端点
return sz*id>n?n:sz*id;
} vector<int>pos[maxn];
int get_count(int val,int l,int r) {
return upper_bound(pos[val].begin(),pos[val].end(),r)-lower_bound(pos[val].begin(),pos[val].end(),l);
} int cnt[maxn];
int mode[maxs][maxs];
int maxt[maxs][maxs];
void ini() {
for(int i=1; i<=n; i++) {
pos[a[i]].push_back(i);
}
// for(int i=1; i<=num; i++) {
// sort(pos[b[i]].begin(),pos[b[i]].end());
// }
for(int i=1; i<=bl; i++) {
int ans=INF;
int tim=0;
for(int j=lb(i); j<=n; j++) {
cnt[a[j]]++;
if(cnt[a[j]]>tim||(cnt[a[j]]==tim&&a[j]<ans)) {
ans=a[j];
tim=cnt[a[j]];
}
if(j%sz==0) {
mode[i][j/sz]=ans;
maxt[i][j/sz]=tim;
}else if(j==n){
mode[i][bl]=ans;
maxt[i][bl]=tim;
}
}
for(int j=lb(i); j<=n; j++) cnt[a[j]]=0;
}
} int query(int l,int r) {
int ans=INF;
int tim=0;
if(id[l]+1<=id[r]-1) {
ans=mode[id[l]+1][id[r]-1];
tim=maxt[id[l]+1][id[r]-1];
}
for(int i=l; i<=min(r,rb(id[l])); i++) {
int tmp=get_count(a[i],l,r);
if(tmp>tim||(tmp==tim&&a[i]<ans)) {
ans=a[i];
tim=tmp;
}
}
if(id[l]!=id[r]) {
for(int i=lb(id[r]); i<=r; i++) {
int tmp=get_count(a[i],l,r);
if(tmp>tim||(tmp==tim&&a[i]<ans)) {
ans=a[i];
tim=tmp;
}
}
}
// return ans;
return b[ans];
} int main() {
int l,r;
qread(n);
qread(m);
for(int i=1; i<=n; i++) {
qread(a[i]);
b[i]=a[i];
}
sort(b+1,b+1+n);
num=unique(b+1,b+1+n)-b-1;
for(int i=1; i<=n; i++) {
a[i]=lower_bound(b+1,b+1+num,a[i])-b;
}
sz=sqrt(n/(log(n)/log(2)));
bl=1;
for(int i=1; i<=n; i++) {
id[i]=bl;
if(i%sz==0) bl++;
}
int x=0;
ini();
for(int i=1; i<=m; i++) {
qread(l);
qread(r);
l=(l+x-1)%n+1;
r=(r+x-1)%n+1;
if(l>r) swap(l,r);
x=query(l,r);
qprint(x);
putchar('\n');
}
}

BZOJ 2724蒲公英 (分块) 【内有块大小证明】的更多相关文章

  1. bzoj 2724 蒲公英 分块

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

  2. BZOJ 2724 蒲公英 | 分块模板题

    题意 给出一个序列,在线询问区间众数.如果众数有多个,输出最小的那个. 题解 这是一道分块模板题. 一个询问的区间的众数,可能是中间"整块"区间的众数,也可能是左右两侧零散的数中的 ...

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

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

  4. BZOJ.2724.[Violet 6]蒲公英(静态分块)

    题目链接 区间众数 强制在线 考虑什么样的数会成为众数 如果一个区间S1的众数为x,那么S1与新区间S2的并的众数只会是x或S2中的数 所以我们可以分块先预处理f[i][j]表示第i到第j块的众数 对 ...

  5. bzoj2906 颜色 分块+块大小分析

    题目传送门 https://lydsy.com/JudgeOnline/problem.php?id=2906 题解 如果可以离线的话,那么这个题目就是一个莫队的裸题. 看上去这个数据范围也还会一个根 ...

  6. 洛谷P4168 蒲公英 分块处理区间众数模板

    题面. 许久以前我还不怎么去机房的时候,一位大佬好像一直在做这道题,他称这道题目为"大分块". 其实这道题目的思想不只可以用于处理区间众数,还可以处理很多区间数值相关问题. 让我们 ...

  7. LibRTMP优化之调整输出块大小

    1. 为什么要调整输出块大小 首先在RTMP_Connect0函数中LibRTMP是关闭了Nagle算法这个TCP选项的,为了实时性这样做是好的,但是要注意到LibRTMP的结构体RTMP的成员是有m ...

  8. Hadoop HDFS 文件块大小

    HDFS 文件块大小 HDFS中的文件在物理上是分块存储(block),块的大小可以通过配置参数( dfs.blocksize)来规定,默认大小在hadoop2.x版本中是128M,老版本中是64M ...

  9. luogu P4168 蒲公英+ 分块学习笔记

    传送门 题目描述 在乡下的小路旁种着许多蒲公英,而我们的问题正是与这些蒲公英有关. 为了简化起见,我们把所有的蒲公英看成一个长度为n的序列\((a_1,a_2..a_n)\),其中 \(a_i\)为一 ...

随机推荐

  1. 图解git中的最常用命令

    图解git中的最常用命令 Git命令参考手册(文本版) git init                                                  # 初始化本地git仓库(创 ...

  2. elasticsearch 基础 —— 处理冲突及乐观并发控制

    处理冲突 当我们使用 index API 更新文档 ,可以一次性读取原始文档,做我们的修改,然后重新索引 整个文档 . 最近的索引请求将获胜:无论最后哪一个文档被索引,都将被唯一存储在 Elastic ...

  3. python3使用print打印带颜色的字符串

    一.实现过程 终端的字符颜色是用转义序列控制的,是文本模式下的系统显示功能,和具体的语言无关 转义序列是以ESC开头,即用\033来完成(ESC的ASCII码用十进制表示是27,用八进制表示就是033 ...

  4. 【Leetcode周赛】从contest-51开始。(一般是10个contest写一篇文章)

    Contest 51 (2018年11月22日,周四早上)(题号681-684) 链接:https://leetcode.com/contest/leetcode-weekly-contest-51 ...

  5. demo board boot mode

    demo扩展板 QSPI0_IO0_MIO2--A13--PS-MIO2 QSPI0_IO0_MIO3--A14--PS-MIO3 QSPI0_IO0_MIO4--B11--PS-MIO4 QSPI0 ...

  6. 什么是网站TDK?

    什么是网站TDK?可能很多新手站长与SEOer不知道.其实TDK就是网站的标题(title).描述(description)和关键词(keyword),TDK是网站很重要的元素,他是蜘蛛爬取你的网站之 ...

  7. UVA11540 Sultan's Chandelier Burnside 引理 + DP

    题目传送门 https://vjudge.net/problem/UVA-11540 https://uva.onlinejudge.org/index.php?option=com_onlineju ...

  8. 01.springboot入门--启用自动配置注解EnableAutoConfiguration

    springboot入门 <parent> <groupId>org.springframework.boot</groupId> <artifactId&g ...

  9. js中require()的用法----JS如何连接数据库执行sql语句或者建立数据库连接池

    var vue = require('vue'); 引入vue的意思,commonjs的写法.node都是用require来载入模块的,可以看看webpack+vue. require()可以调用模块 ...

  10. 命令行启动appium服务

    Android终端 appium --avd test -a 127.0.0.1 -p 4723 --language "zh_CN" --locale "CN" ...