题面

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. java中位运算^,&,<<,>>,<<<,>>>总结

    1.^(亦或运算) ,针对二进制,相同的为0,不同的为1 public static void main(String[] args) { System.out.println("2^3运算 ...

  2. JS中的reduce函数

    海纳百川,有容乃大 定义: reduce()方法接受一个函数作为累加器,数组中的每个值(从左向右)开始缩减,最终计算为一个值.对空数组是不会执行回调函数的. 案例: 计算数组总和: var num = ...

  3. CSS-03 queue方法

    queue方法 摘自W3C school手册,用于简单理解使用queue方法 队列 每个元素均可拥有一到多个由 jQuery 添加的函数队列.在大多数应用程序中,只使用一个队列(名为 fx).队列运行 ...

  4. linux学习-系统监控工具

    系统监控工具 come from:https://blog.csdn.net/free050463/article/details/82842273top.free.vmstat.iostat.pma ...

  5. $Noip$前的小总结哦

    考试失误点与积累 有点不知道该干嘛了,状态有点差,写点东西.(后面可能会加更一点东西?) 常规错误 \(1.\) 数组开小 \(2.\) \(int\)和\(longlong\) \(3.\) 开某题 ...

  6. webRTC脱坑笔记(二)— webRTC API之MediaStream(getUserMedia)

    webRTC API WebRTC API包括媒体捕获.音频视频的编码和解码.传输层和会话管理. getUserMedia():捕获音频和视频. MediaRecorder:录制音频和视频. RTCP ...

  7. @PostMapping

    @PostMapping映射一个POST请求 Spring MVC新特性 提供了对Restful风格的支持 @GetMapping,处理get请求 @PostMapping,处理post请求 @Put ...

  8. Python格式输出汇总

    print ('%10s'%('test')) print ('{:<10}'.format('test'))#left-aligned print ('{:>10}'.format('t ...

  9. C#基础提升系列——C#文件和流

    C#文件和流 本文主要是对C#中的流进行详细讲解,关于C#中的文件操作,考虑到后期.net core跨平台,相关操作可能会发生很大变化,所以此处不对文件系统(包括目录.文件)过多的讲解,只会描述出在. ...

  10. Struts和Hibernate的jar包

    这几天做了一个javaee关于struts框架和Hibernate框架的实践,实践内容倒是没什么,关键是找框架的配置花了许多时间 于是在这里把这两个框架的有关jar上传分享一下 链接: https:/ ...