题目传送门

题意

长度为n的序列,有m次询问,每次询问求\([l,r]\) 间的众数,如果有多个,输出最小的那个

\(n\le 4\times 10^4,m\le 5\times 10^5,a_i\le10^9\)

分析

题目中要求在线(询问用上次答案加密)。众数不具有“区间可加性”,所以需要分块。

假设分成\(T\)块,每块长度\(L=N/T\)。每次询问\([l,r]\),设\(l\)处在\(p\)块,\(r\)处在\(q\)块,则区间分为三部分。

  • 开头的\([l,L)\)
  • \(第p+1\sim q-1块构成的区间[L,R]\)
  • 结尾的\((R,r]\)

    显然序列在整个询问区间的众数只可能出现在\([L,R]\)中的众数,或者头尾出现的数字中。

    可以预处理所有分块区间的众数\(d[l][r]\)表示\(l\)块到\(r\)块中的众数。复杂度\(O(TN)\)

    对于头尾的部分,暴力枚举每个数字,通过预先存在每个数字出现的位置,这样就可以二分查询该数字\([l,r]\)出现的次数,然后选取最大的即可。复杂度\(NM/T*log(N)\)

    所以总复杂度为\(O(TN+NM/T*log(N))\),又N和M几乎同级,可得\(T = \sqrt{Mlog(N)}\)时较优。

    更多细节请看代码

思路&步骤

  1. 存下每个数字,离散化,处理每个数字出现的位置,储存在STL::vector里面
  2. 分块,预处理整区间的众数
  3. 查询,先取整个区间的答案,然后两头扫
#include <bits/stdc++.h>
using namespace std;
const int N = 40010;
const int M = 500010;
/*
be[i] 表示 i 在第几块
id[i] 表示a[i]在离散化数组中的位置
blc为块大小
cnt[i] 预处理时需要的数组,表示 i 的个数
d[i][j]表示 i块与 j块之间的众数
v[i] 表示 数字 i 出现的位置
g为离散化vector
*/
int be[N],id[N],a[N],n,m;
int blc,cnt[N],d[1200][1200];
vector<int> v[N],g; int getID(int x){
return lower_bound(g.begin(),g.end(),x) - g.begin();
}
//预处理整块区间众数
void build(int x){
int res = -1;
for(int i=0;i<g.size();i++)cnt[i] = 0;
for(int i=(x-1)*blc+1;i<=n;i++){
cnt[id[i]] ++;
if(res == -1 || cnt[id[i]] > cnt[res] || (cnt[id[i]] == cnt[res] && id[i] < res)){
res = id[i];
}
d[x][be[i]] = res;
}
}
//询问[l,r]间x的个数
int ask(int l,int r,int x){
return upper_bound(v[x].begin(),v[x].end(),r) - lower_bound(v[x].begin(),v[x].end(),l);
}
int query(int l,int r){
//mxcnt为当前众数的个数,res为答案
int mxcnt = 0,res = -1;
if(be[r] - be[l] > 1){
res = d[be[l]+1][be[r]-1];
mxcnt = ask(l,r,res);
}
if(be[r] == be[l]){
for(int i=l;i<=r;i++){
int cnt = ask(l,r,id[i]);
if(res == -1 || mxcnt < cnt || (mxcnt == cnt && id[i] < res)){
res = id[i];
mxcnt = cnt;
}
}
}
else{
for(int i=l;i<=be[l] * blc;i++){
int cnt = ask(l,r,id[i]);
if(res == -1 || mxcnt < cnt || (mxcnt == cnt && id[i] < res)){
res = id[i];
mxcnt = cnt;
}
}
for(int i=(be[r]-1) * blc;i<=r;i++){
int cnt = ask(l,r,id[i]);
if(res == -1 || mxcnt < cnt || (mxcnt == cnt && id[i] < res)){
res = id[i];
mxcnt = cnt;
}
}
}
return res;
}
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
g.push_back(a[i]);
}
sort(g.begin(),g.end());g.erase(unique(g.begin(),g.end()),g.end());
for(int i=1;i<=n;i++){
id[i] = getID(a[i]);
v[id[i]].push_back(i);
}
blc = max(1,(int)(n/sqrt(m * log2(n))));
for(int i=1;i<=n;i++){
be[i] = (i-1) / blc + 1;
}
for(int i=1;i<=be[n];i++)
build(i);
int res = 0;
while(m--){
int l,r;
scanf("%d%d",&l,&r);
l = (l + res - 1) % n + 1;
r = (r + res - 1) % n + 1;
if(l > r)swap(l,r);
res = g[query(l,r)];
printf("%d\n",res);
}
return 0;
}

Luogu4168 蒲公英 (分块)的更多相关文章

  1. luogu4168蒲公英(区间众数)

    luogu4168蒲公英(区间众数) 给定n个数,m个区间询问,问每个询问中的众数是什么. 题面很漂亮,大家可以去看一下. 对于区间众数,由于区间的答案不能由子区间简单的找出来,所以似乎不能用树形结构 ...

  2. BZOJ 2724: [Violet 6]蒲公英( 分块 )

    虽然AC了但是时间惨不忍睹...不科学....怎么会那么慢呢... 无修改的区间众数..分块, 预处理出Mode[i][j]表示第i块到第j块的众数, sum[i][j]表示前i块j出现次数(前缀和, ...

  3. [Violet]蒲公英 分块

    发现写算法专题老是写不动,,,, 所以就先把我在luogu上的题解搬过来吧! 题目大意:查询区间众数,无修改,强制在线 乍一看是一道恐怖的题,仔细一看发现并没有那么难: 大致思路是这样的,首先我们要充 ...

  4. 【BZOJ2724】[Violet 6]蒲公英 分块+二分

    [BZOJ2724][Violet 6]蒲公英 Description Input 修正一下 l = (l_0 + x - 1) mod n + 1, r = (r_0 + x - 1) mod n ...

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

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

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

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

  7. BZOJ 2724: [Violet 6]蒲公英 [分块 区间众数]

    传送门 题面太美不忍不放 分块分块 这种题的一个特点是只有查询,通常需要预处理:加入修改的话需要暴力重构预处理 预处理$f[i][j]$为第i块到第j块的众数,显然$f[i][j]=max{f[i][ ...

  8. bzoj 2724 蒲公英 分块

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

  9. BZOJ2724 [Violet 6]蒲公英 分块

    原文链接https://www.cnblogs.com/zhouzhendong/p/BZOJ2724.html 题目传送门 - BZOJ2724 题意 求区间最小众数,强制在线. $n$ 个数,$m ...

随机推荐

  1. Maven项目编译之后xml文件不存在

    如题: 问题请看图,target目录是编译之后的,发现并没有对应的mapper.xml文件 原因: maven项目默认不加载此类文件 解决办法有两个: 其一是将mybatis的xml映射文件放在mav ...

  2. 【Linux】java.io.IOException: error=24, Too many open files解决

    linux系统中执行java程序的时候,如果打开文件超过了限制,就会报错: java.io.IOException: error=24, Too many open files 解决办法: 首先查看j ...

  3. 【老孟Flutter】源码分析系列之InheritedWidget

    老孟导读:这是2021年源码系列的第一篇文章,其实源码系列的文章不是特别受欢迎,一个原因是原理性的知识非常枯燥,我自己看源码的时候特别有感触,二是想把源码分析讲的通俗易懂非常困难,自己明白 和 让别人 ...

  4. [GKCTF2020]老八小超市儿

    题目来自buu 一.题目初探 首先是一个shopxo搭建的演示站,通过扫描后台得到如下的网页 二.题目解答 首先是找到后台登陆的admin.php,然后通过百度找到shopxo的默认管理员登陆账号和密 ...

  5. K8s遇到问题解决思路

    问题排查一 从describe去查找相应的deploy/pod/rs/svc [root@k8s-master ~]# kubectl describe po/nginx-f95d765f9-8b6b ...

  6. 单元测试:单元测试中的mock

    公司要求提升单元测试的质量,提高代码的分支覆盖率和行覆盖率,安排我研究单元测试,指定方案分享并在开发部普及开.整理完资料后,同步一下到博客. 单元测试中的mock的目的 mock的主要目的是让单元测试 ...

  7. python中hmac模块的使用

    hmac(hex-based message authentication code)算法在计算哈希的过程中混入了key(实际上就是加盐),和hashlib模块中的普通加密算法相比,它能够防止密码被撞 ...

  8. python-列表包字典-根据字典的某一个键的值来进行排序

    python-列表包字典-根据字典的某一个键的值来进行排序 列表包字典的数据结构 要实现按照字典中的某一个键所对应的值进行排序 有两种办法 方法一,使用列表的sort方法 由小到大排 列表.sort( ...

  9. 太极图HTML+CSS(可旋转)代码记录

    <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...

  10. 炸裂!MySQL 82 张图带你飞

    之前两篇文章带你了解了 MySQL 的基础语法和 MySQL 的进阶内容,那么这篇文章我们来了解一下 MySQL 中的高级内容. 其他文章: 138 张图带你 MySQL 入门 47 张图带你 MyS ...