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 ...
随机推荐
- 抽签小程序,妈妈再也不用担心谁洗碗(分配任务)了,so easy
背景 今天谁炒菜,谁洗碗,谁买菜...啊,Boss说用抽签吧,于是有了下图 这样存在作弊的问题(记住棍子特征,谁先,谁后抽等等)于是有了这个抽签小程序(当然小程序我一个人控制,我想不想作弊看心情了) ...
- 初探CI,Github调戏Action手记——自动构建并发布
前言 最近在做脚本的说明文档时使用了vuepress这个东西 前端实在是菜,只能随便写写了 正常写完md文件之后推送至github做版本控制 而前端页面的生成则是在本地,部署也是在本地手工进行 一套下 ...
- bat中的特殊字符,以及需要在bat中当做字符如何处理
bat中的特殊字符,以及需要在bat中当做字符如何处理 (2014-02-27 21:16:55) 转载▼ 标签: bat 特殊字符 分类: develop bat中的特殊字符,以及需要在bat中当做 ...
- AJ学IOS 之二维码学习,快速打开相机读取二维码
AJ分享,必须精品 上一篇文章写了怎么生成二维码,这儿就说说怎么读取吧,反正也很简单,iOS封装的太强大了 步骤呢就是这样: 读取二维码需要导入AVFoundation框架#import <AV ...
- 也谈如何实现bind、apply、call
也谈如何实现bind.apply.call 我们知道,JavaScript的bind.apply.call是三个非常重要的方法.bind可以返回固定this.固定参数的函数包装:apply和call可 ...
- Go语言讲解深拷贝与浅拷贝
我们在开发中会经常的把一个变量复制给另一个变量,那么这个过程,可能是深浅拷贝,那么今天帮大家区分一下这两个拷贝的区别和具体的区别. 一.概念 1.深拷贝(Deep Copy): 拷贝的是数据本身,创造 ...
- sublime text3添加并修改编译系统
版权声明:本文为CSDN博主「肥宅_Sean」的原创文章,遵循 CC 4.0 BY-SA 版权协议,原文链接 方法工具 -> 编译系统 -> 新建编译系统 按ctrl+s保存.(注意,这里 ...
- 爬虫的新手使用教程(python代理IP)
前言 Python爬虫要经历爬虫.爬虫被限制.爬虫反限制的过程.当然后续还要网页爬虫限制优化,爬虫再反限制的一系列道高一尺魔高一丈的过程.爬虫的初级阶段,添加headers和ip代理可以解决很多问题. ...
- Daily Scrum 12/23/2015
Process: Zhaoyang: Compile the Caffe IOS version and make it run in the IOS9. Yandong: Finish the Az ...
- D. Points in rectangle
D. Points in rectangle 单点时限: 2.0 sec 内存限制: 512 MB 在二维平面中有一个矩形,它的四个坐标点分别为(0,a),(a,0),(n,n−a),(n−a,n). ...