P4168 蒲公英
神仙分块,把减写成加调了半小时。。
不过这题也启示我们其实有的分块题要把多个块的信息拿到一起维护
以前做的都是每个块的信息单独维护
写的分块题还不太多,同时维护一个块的左右边界好像有点冗余,不过这样代码看起来更简单
题意
给你长度为\(n\)的数组\(a\),\(m\)次询问,每次询问\([l,r]\)的众数
如果众数有多个,输出最小的一个
强制在线
输入格式
第一行两个整数\(n,m\) ,表示有\(n\)株蒲公英,\(m\) 次询问。
接下来一行n个空格分隔的整数\(a_i\),表示蒲公英的种类
再接下来m 行每行两个整数\(l_0,r_0\),我们令上次询问的结果为\(x\)(如果这是第一次询问, 则 \(x=0\))。
令 \(l=(l_0+x-1)\bmod n + 1,r=(r_0+x-1) \bmod n +1\),如果 \(l>r\),则交换 \(l,r\) 。
最终的询问区间为\([l,r]\)。
输出格式
输出\(m\) 行。每行一个整数,表示每次询问的结果。
数据范围
对于 100% 的数据,保证\(1\leq n \leq 40000,1\leq m \leq 50000,1\leq a_i \leq 10^9\)
首先看到\(a_i\leq 10^9\),这题的问题有和每个数的数值有关系,所以考虑先离散化
一般使用分块时,如果\(l,r\)在同一个块或者在两个相邻的块(即\(belong_r-belong_l\leq 1\)),肯定是要暴力处理,复杂度\(O(\sqrt{n})\)
所以先考虑这部分怎么做
可以开一个\(tmp\)数组,\(tmp_i\)表示\(i\)这个值(肯定是离散化以后的值)出现了多少次
然后再用一个\(maxpos\)指向当前出现数量最多的数,一旦\(tmp_i>tmp_{maxpos}\)或者\(tmp_i=tmp_{maxpos},i<maxpos\),就让\(maxpos\)指向\(i\)
然后最后的\(maxpos\)就是我们要找的众数,复杂度可以是\(O(r-l)\),在\(r-l\)远小于\(n\)的时候应该用这种方法,在这里就是\(O(\sqrt{n})\)
再去考虑其它情况
对于\([l,r]\),我们设它们之间包含的整的块的区间是\([l',r']\),也就是说\([l,l'),(r',r]\)分别是左右两边的边角块
那么\([l,r]\)的众数有两种情况
- \([l,l'),(r',r]\)中的数,在\([l,r]\)的出现次数最多的那个,也小于\([l',r']\)的众数在\([l,r]\)的出现次数,那么\([l,r]\)的众数就是\([l',r']\)的众数
- \([l,l'),(r',r]\)中的数,在\([l,r]\)的出现次数最多的那个,大于\([l',r']\)的众数在\([l,r]\)的出现次数,或者他们相等,但这个数比\([l',r']\)的众数要小,那么\([l,r]\)的众数肯定就是这个数
当然上面说的“最多”,也是如果一样多就取数值较小的
关于怎么求\([l,l'),(r',r]\)中每个数在\([l,r]\)的出现次数,首先还是像那个暴力一样,统计这些数在左右边角块的出现次数
再用一个\(tag_i\)表示\(i\)这个数,目前有没有统计在\([l',r']\)的出现次数,如果统计了就不在加了,如果没有统计就加上他在\([l',r']\)的出现次数,然后\(tag_i=1\)
在\([l',r']\)中的次数,我们可以维护一个\(sum_{i,j}\)表示前\(i\)个块,\(j\)出现了几次,就是个前缀和,一减就行
那么我们预处理的时候,要预处理出对于任意\(r\geq l\),第\(l\)个块到第\(r\)个块的众数
这个可以枚举每个\(l\),用之前暴力做法去做,就是每累计一个块记录一次答案,然后累计到最后一个块再清空,复杂度\(O(n\sqrt{n})\)
再就是之前说的那个前缀和,直接按定义求就行
然后\(tmp,tag\)的归零都不能用 memset ,否则就又成\(O(n)\)了,要一位位把之前改变过的位数清零,具体怎么做看代码
话说分块都好毒瘤,这题也是看了题解,然后知道了要维护那两个量才会的
不过好多题解都上来就把要预处理什么说出来,就体现不出思考的过程了
思考的时候肯定也是先想如果要求答案要知道什么,而不是先猜这个题要预处理出什么
如果是个套路题除外
#include<cstdio>
#include<algorithm>
#include<iostream>
#include<cmath>
#include<iomanip>
#include<cstring>
#define reg register
#define EN std::puts("")
#define LL long long
inline int read(){
int x=0,y=1;
char c=std::getchar();
while(c<'0'||c>'9'){if(c=='-') y=0;c=std::getchar();}
while(c>='0'&&c<='9'){x=x*10+(c^48);c=std::getchar();}
return y?x:-x;
}
int n,m,block,blocknum,maxx;
int f[206][205],sum[206][40006];
int belong[40006];
int left[206],right[206];
int tmp[40006],maxpos,tag[40006];
struct data{
int num,id,x;
}a[40006];
int what[40006];
inline void debug(){
std::printf("blocknum : %d blocksize : %d\n",blocknum,block);
std::printf("what : ");for(reg int i=1;i<=maxx;i++) std::printf("%d ",what[i]);EN;
for(reg int i=1;i<=n;i++) std::printf("%d ",a[i].x);EN;
for(reg int i=1;i<=blocknum;i++){
std::printf("%d : ",i);
for(reg int j=1;j<=maxx;j++) std::printf("%d ",sum[i][j]);
EN;
}
for(reg int i=1;i<=blocknum;i++){
for(reg int j=i;j<=blocknum;j++) std::printf("(%d %d): %d ",i,j,f[i][j]);
EN;
}
}
inline int cmp(data x,data y){return x.num<y.num;}
inline int cmp2(data x,data y){return x.id<y.id;}
inline void pre(){
for(reg int i=1;i<=blocknum;i++){
for(reg int j=1;j<=maxx;j++) sum[i][j]=sum[i-1][j];
for(reg int j=left[i];j<=right[i];j++) sum[i][a[j].x]++;
}
for(reg int i=1;i<=blocknum;i++){
for(reg int j=i;j<=blocknum;j++){
for(reg int k=left[j];k<=right[j];k++){
tmp[a[k].x]++;
if(a[k].x==maxpos) continue;
if(tmp[a[k].x]>tmp[maxpos]||(tmp[a[k].x]==tmp[maxpos]&&a[k].x<maxpos)) maxpos=a[k].x;
}
f[i][j]=maxpos;
}
std::memset(tmp,0,sizeof tmp);maxpos=0;
}
}
inline int baoli(int l,int r){
for(reg int i=l;i<=r;i++){
tmp[a[i].x]++;
if(a[i].x==maxpos) continue;
if(tmp[a[i].x]>tmp[maxpos]||(tmp[a[i].x]==tmp[maxpos]&&a[i].x<maxpos)) maxpos=a[i].x;
}
for(reg int i=l;i<=r;i++) tmp[a[i].x]=0;
int ret=maxpos;maxpos=0;
return ret;
}
inline int getans(int l,int r){
reg int lblock=belong[l]+(left[belong[l]]!=l),rblock=belong[r]-(right[belong[r]]!=r);
for(reg int i=l;i<left[lblock];i++){
tmp[a[i].x]++;
if(!tag[a[i].x]) tmp[a[i].x]+=sum[rblock][a[i].x]-sum[lblock-1][a[i].x],tag[a[i].x]=1;
if(a[i].x==maxpos) continue;
if(tmp[a[i].x]>tmp[maxpos]||(tmp[a[i].x]==tmp[maxpos]&&a[i].x<maxpos)) maxpos=a[i].x;
}
for(reg int i=right[rblock]+1;i<=r;i++){
tmp[a[i].x]++;
if(!tag[a[i].x]) tmp[a[i].x]+=sum[rblock][a[i].x]-sum[lblock-1][a[i].x],tag[a[i].x]=1;
if(a[i].x==maxpos) continue;
if(tmp[a[i].x]>tmp[maxpos]||(tmp[a[i].x]==tmp[maxpos]&&a[i].x<maxpos)) maxpos=a[i].x;
}
if(!tag[f[lblock][rblock]]) tmp[f[lblock][rblock]]=sum[rblock][f[lblock][rblock]]-sum[lblock-1][f[lblock][rblock]];
int ret;
if(tmp[maxpos]>tmp[f[lblock][rblock]]||(tmp[maxpos]==tmp[f[lblock][rblock]]&&maxpos<f[lblock][rblock])) ret=maxpos;
else ret=f[lblock][rblock];
for(reg int i=l;i<left[lblock];i++) tmp[a[i].x]=tag[a[i].x]=0;
for(reg int i=right[rblock]+1;i<=r;i++) tmp[a[i].x]=tag[a[i].x]=0;
tmp[f[lblock][rblock]]=tag[f[lblock][rblock]]=0;
return ret;
}
int main(){
n=read();m=read();block=std::sqrt(n);
blocknum=std::ceil((double)n/block);
left[1]=1;right[blocknum]=n;
for(reg int i=1;i<=n;i++){
a[i].num=read(),a[i].id=i;
belong[i]=(i-1)/block+1;
if(belong[i]!=belong[i-1]) left[belong[i]]=i,right[belong[i-1]]=i-1;
}
std::sort(a+1,a+1+n,cmp);
maxx=0;
for(reg int i=1;i<=n;){
a[i].x=++maxx;what[maxx]=a[i].num;
reg int last=i;
for(i++;a[last].num==a[i].num;i++) a[i].x=maxx;
}
std::sort(a+1,a+1+n,cmp2);
pre();
// debug();
reg int ans=0,l,r;
while(m--){
l=read();r=read();
l=(l+ans-1)%n+1;r=(r+ans-1)%n+1;
if(r<l) l^=r,r^=l,l^=r;
if(belong[r]-belong[l]<=1) ans=baoli(l,r);
else ans=getans(l,r);
ans=what[ans];
std::printf("%d\n",ans);
}
return 0;
}
P4168 蒲公英的更多相关文章
- luogu P4168 蒲公英+ 分块学习笔记
传送门 题目描述 在乡下的小路旁种着许多蒲公英,而我们的问题正是与这些蒲公英有关. 为了简化起见,我们把所有的蒲公英看成一个长度为n的序列\((a_1,a_2..a_n)\),其中 \(a_i\)为一 ...
- 洛谷P4168 蒲公英 分块处理区间众数模板
题面. 许久以前我还不怎么去机房的时候,一位大佬好像一直在做这道题,他称这道题目为"大分块". 其实这道题目的思想不只可以用于处理区间众数,还可以处理很多区间数值相关问题. 让我们 ...
- 洛谷P4168 蒲公英 [Violet] 分块
题解:分块+离散化 解题报告: 一个分块典型题呢qwq还是挺妙的毕竟是道黑题 然,然后发现忘记放链接了先放链接QAQ 有两三种解法,都港下qwq 第一个是O(n5/3)的复杂度,谢总说不够优秀没有港, ...
- 洛谷 P4135 作诗 题解
题面. 之前做过一道很类似的题目 洛谷P4168蒲公英 ,然后看到这题很快就想到了解法,做完这题可以对比一下,真的很像. 题目要求区间内出现次数为正偶数的数字的数量. 数据范围1e5,可以分块. 我们 ...
- 洛谷 P4168 [Violet]蒲公英 解题报告
P4168 [Violet]蒲公英 题目背景 亲爱的哥哥: 你在那个城市里面过得好吗? 我在家里面最近很开心呢.昨天晚上奶奶给我讲了那个叫「绝望」的大坏蛋的故事的说!它把人们的房子和田地搞坏,还有好多 ...
- P4168 [Violet]蒲公英 区间众数
$ \color{#0066ff}{ 题目描述 }$ 在乡下的小路旁种着许多蒲公英,而我们的问题正是与这些蒲公英有关. 为了简化起见,我们把所有的蒲公英看成一个长度为n的序列 \((a_1,a_2.. ...
- 「分块系列」「洛谷P4168 [Violet]」蒲公英 解题报告
蒲公英 Description 我们把所有的蒲公英看成一个长度为\(n\)的序列(\(a_1,a_2,...a_n\)),其中\(a_i\)为一个正整数,表示第i棵蒲公英的种类的编号. 每次询问一个区 ...
- 洛谷 P4168 [Violet] 蒲公英
历尽千辛万苦终于AC了这道题目... 我们考虑1个区间\([l,r]\), 被其完整包含的块的区间为\([L,R]\) 那么众数的来源? 1.\([l,L)\)或\((R,r]\)中出现的数字 2.\ ...
- P4168 [Violet]蒲公英
神仙分块题?其实还是很简单的,res[i][j]表示第i块到第j块的众数,然后再用sum[i][j]表示前i块中j这个种类出现的次数,然后分块瞎搞就行了,感觉我写的十分简洁,好评( //author ...
随机推荐
- Linux bash篇(二 操作环境)
1.命令执行的顺序 (1).相对/绝对路径 (2).由alias找到的命令 (3).由bash内置的命令 (4).通过$PATH变量找到的第一个命令 2.第一篇讲到的bash在注销后就会无效,如果想保 ...
- jQuery extend()和jQuery.fn.extend()区别和详解
1.认识jQuery extend()和jQuery.fn.extend() jQuery的API手册中,extend方法挂载在jQuery和jQuery.fn两个不同对象上方法,但在jQuery内部 ...
- Golang源码分析之目录详解
开源项目「go home」聚焦Go语言技术栈与面试题,以协助Gopher登上更大的舞台,欢迎go home~ 导读 学习Go语言源码的第一步就是了解先了解它的目录结构,你对它的源码目录了解多少呢? 目 ...
- shell命令-while语句
loop=1 while [ "$loop" -le 10 ] do echo "loop:$loop" loop=$(($loop+2)) done
- 设置xml以让通知spring 扫描 注解
<!--下边三个都是告诉spring扫描注解--> 一.<context:component-scan base-package="log.logback"/&g ...
- 概率专题_概率/ 数学_基础题_ABEI
上周三讲了概率和概率dp.如果没有涉及其他综合算法,概率这种题主要是思维,先把这部分的东西写完 给个题目链接:https://vjudge.net/contest/365300#problem Hea ...
- Nginx+uWSGI+Python+Django构建必应高清壁纸站
写在前面 做这个网站的初衷是因为,每次打开必应搜索搜东西的时候都会被上面的背景图片吸引,我想必应的壁纸应该是经过专业人员精选出来的,我甚至会翻看以前的历史图片,唯一美中不足的是必应的首页只能查看最多7 ...
- 使用原生js实现选项卡功能实例教程
选项卡是前端常见的基本功能,它是用多个标签页来区分不同内容,通过选择标签快速切换内容.学习本教程之前,读者需要具备html和css技能,同时需要有简单的javascript基础. 先来完成html部分 ...
- Jenkins 批量创建任务的三种方法
最近,要搭建多套测试环境,需要把 Jenkins 中 dev 视图下的所有任务批量复制到 sit 等视图下. 说明 Jenkins 任务名称规则为:[测试环境标识]-[工程名称],如:dev-daod ...
- 原创Hbase1.2.1集群安装
[hadoop@Hmaster install]$ tar -zxvf hbase-1.2.1-bin.tar.gz -C ~ [hadoop@Hmaster install]$vi ~/.bash_ ...