题面

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. Mint-Linux【最佳】【快速】安装微信、企业微信、TIM、QQ等软件

    废话不多说 直接上教程 注意看 方式一.在线安装 在本地目录下.如 /home/root/Document 直接使用在线安装脚本,安装最新的Release版本: wget -qO- https://r ...

  2. 76.Longest Consecutive Sequence(最长的连续序列)

    Level:   Hard 题目描述: Given an unsorted array of integers, find the length of the longest consecutive ...

  3. zabbix4.0短信告警配置

    #!/usr/bin/env python3 import requests import sys #http://utf8.api.smschinese.cn/?Uid=USERNAME&K ...

  4. rtp/rtcp

    rtp/rtcp stack custom rtp ORTP UCL Common RTP library Bell Labs RTP Library jrtplib 1.custom rtp sen ...

  5. 六、SQL语句进行多条件查询,并解决参数为空的情况

    一.SQL语句进行多条件查询,并解决参数为空的情况 QueryEntity query; var whereSql = new StringBuilder("Where 1=1") ...

  6. Codeforces Round #392 (Div. 2) - A

    题目链接:http://codeforces.com/contest/758/problem/A 题意:给定N个城市的福利,国王现在想让每个城市的福利都一致.问最少需要花多少钱使得N个城市的福利值都一 ...

  7. linux安装jdk环境(多种方式)

    通过tar.gz压缩包安装 此方法适用于绝大部分的linux系统 1.先下载tar.gz的压缩包,这里使用官网下载. 进入: http://www.oracle.com/technetwork/jav ...

  8. 2019CCPC网络预选赛 1003 K-th occurrence 后缀自动机 + 二分 + 主席树

    题意:给你一个长度为n的字符串,有m次询问,每次询问l到r的子串在原串中第k次出现的位置,如果没有输出-1.n, m均为1e5级别. 思路:后悔没学后缀数组QAQ,其实只要学过后缀数组这个题还是比较好 ...

  9. linux内核启动过程

    作者:严哲璟 原创作品转载请注明出处 + <Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-1000029000 通过qemu以 ...

  10. sass-RGB颜色函数-RGBA()函数

    rgba() 函数主要用来将一个颜色根据透明度转换成 rgba 颜色. 其语法有两种格式: rgba($red,$green,$blue,$alpha) //将一个rgba颜色转译出来,和未转译的值一 ...