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 ...
随机推荐
- 汇编刷题:统计2000H开始的正负数的个数
DATA SEGMENT ORG 2000H INFO DB 1,2,3,4,5,70H,71H,72H,80H,92H N_NUMS DB 00H P_NUMS DB 00H DATA ENDS C ...
- gcc/g++堆栈保护技术
最近学习内存分布,通过gdb调试发现一些问题,栈空间变量地址应该是从高往低分布的,但是调试发现地址虽然是从高往低分布,但是变量地址的顺序是乱的,请教同事他说可能是gcc/g++默认启用了堆栈保护, ...
- 在MAC上如何使用SQL Server
由于小编在这学期要学习数据库原理这门课程,需要用到SQL Server,然而大家都知道SQL Server目前是只能在Windows上使用,我们在mac电脑上如何使用呢?我们可以借助目前比较火的Doc ...
- sparkRdd driver和excuter
//1 从内存中创建makeRdd,底层实现就是parallelize val rdd=sc.makeRDD(Array(1,2,"df",55)) //2 从中创建paralle ...
- 理解class.forName() ---使用jdbc方式链接数据库时会经常看到这句代码
目录(?)[-] 官方文档 类装载 两种装载方法的区别 不同的类装载器 是否实例化类 在jdbc链接数据库中的应用 资源 原文地址:http://yanwushu.sinaapp.com/clas ...
- L20 梯度下降、随机梯度下降和小批量梯度下降
airfoil4755 下载 链接:https://pan.baidu.com/s/1YEtNjJ0_G9eeH6A6vHXhnA 提取码:dwjq 梯度下降 (Boyd & Vandenbe ...
- Equalizing by Division
The only difference between easy and hard versions is the number of elements in the array. You are g ...
- Git敏捷开发--rebase命令
git rebase是git下比较常用的命令,以下记录自己遇到较多的使用场景. 合并分支 在多人协作的项目中,拉分支是很常见的事情,经常需要同步自己的分支与远端master分支一致,有两种方式: gi ...
- 图解Knative核心组件Serving基础设计
最近闲下来,打算把Knative的核心组件Serving给学习下,会继续采用k8s源码学习的方式,管中窥豹以小击大,学习serving的主要目标: 可观测性基础设施.自动伸缩.流量管理等核心组件的设计 ...
- 基于nodejs的游戏服务器
开源一个四年前自己写的node服务器,有兴趣的可以继续开发-- 架构为mysql,redis,node. 数据格式为 protocol buff 如果只做简单的演示,这个架构非常适合你.. 还是typ ...