luogu P4168 蒲公英+ 分块学习笔记
## [ 传送门 ](https://www.luogu.org/problemnew/show/P4168)
题目描述
在乡下的小路旁种着许多蒲公英,而我们的问题正是与这些蒲公英有关。
为了简化起见,我们把所有的蒲公英看成一个长度为n的序列\((a_1,a_2..a_n)\),其中 \(a_i\)为一个正整数,表示第i棵蒲公英的种类编号。
而每次询问一个区间 [l,r],你需要回答区间里出现次数最多的是哪种蒲公英,如果有若干种蒲公英出现次数相同,则输出种类编号最小的那个。
注意,你的算法必须是在线的
Solution
分块
但是要维护些什么呢?
假设我们已经对原序列进行了分块,对于一个询问\([l,r]\),我们所寻求的答案很大概率出现在中间的完整的块中,否则,它就一定在两边离散的数中出现过,而这些数是不超过\(2 \sqrt n\)的。
所以,我们只要维护一个 \(ans[i][j]\)表示第i块到第j块的答案,这个初始化时\(O(n \sqrt n)\)的。
还有就是每个数的出现次数,\(num[x][i]\)表示数x在前i块出现的次数
不过,如果打得不够优美的话是要TLE的。。。
Code
#include<bits/stdc++.h>
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
inline int read()
{
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}
return x*f;
}
#define MN 40005
int N,M,col[MN],fcol[MN],tt[MN],tot;
int T,pos[MN],a[205][205],num[MN][205],L[MN],R[MN];
inline void init()
{
register int i,j;
std::sort(tt+1,tt+tot+1);
tot=std::unique(tt+1,tt+tot+1)-tt-1;
for(i=1;i<=N;++i)
{
int p=col[i];
col[i]=std::lower_bound(tt+1,tt+tot+1,col[i])-tt;
fcol[col[i]]=p;
}
for(i=N;i>=1;--i)
{
if(pos[i]==pos[i-1]) continue;
L[pos[i]]=i;
register int ans=0,bl=pos[i];
for(j=i;j<=N;++j)
{
num[col[j]][bl]++;
if(num[col[j]][bl]>num[ans][bl]) ans=col[j];
if(num[col[j]][bl]==num[ans][bl]&&col[j]<ans) ans=col[j];
if(pos[j]!=pos[j+1]) R[pos[j]]=j,a[pos[i]][pos[j]]=ans;
}
}
memset(num,0,sizeof num);
for(i=1;i<=N;++i)
{
num[col[i]][pos[i]]++;
if(pos[i]!=pos[i+1]&&i!=N)
for(j=1;j<=tot;++j) num[j][pos[i]+1]=num[j][pos[i]];
}
}
int tmp[MN];
bool vis[MN];
inline int query(int l,int r)
{
memset(tmp,0,sizeof tmp);
memset(vis,0,sizeof vis);
register int i,ll,rr,ans=0;
ll=pos[l]+(l!=L[pos[l]]);
rr=pos[r]-(r!=R[pos[r]]);
if(l!=L[pos[l]])
for(i=l;i<=R[pos[l]];++i)
{
tmp[col[i]]++;
if(!vis[col[i]]) vis[col[i]]=true,tmp[col[i]]+=num[col[i]][rr]-num[col[i]][ll-1];
if(tmp[col[i]]>tmp[ans]||(tmp[ans]==tmp[col[i]]&&col[i]<ans)) ans=col[i];
}
if(r!=R[pos[r]])
for(i=L[pos[r]];i<=r;++i)
{
tmp[col[i]]++;
if(!vis[col[i]]) vis[col[i]]=true,tmp[col[i]]+=num[col[i]][rr]-num[col[i]][ll-1];
if(tmp[col[i]]>tmp[ans]||(tmp[ans]==tmp[col[i]]&&col[i]<ans)) ans=col[i];
}
register int o=a[ll][rr],numo=num[o][rr]-num[o][ll-1];
// printf("ll=%d rr=%d o=%d\n",ll,rr,o);
if(!vis[o]&&(numo>tmp[ans]||(numo==tmp[ans]&&o<ans))) ans=o;
return fcol[ans];
}
int main()
{
// freopen("testdata.in","r",stdin);
// freopen("tesedata.out","w",stdout);
N=read();M=read();
register int i;T=(int)(sqrt(N));
for(i=1;i<=N;++i) col[i]=read(),pos[i]=(i-1)/T+1,tt[++tot]=col[i];
init();
int l,r,x=0;
// L=(l0-1+x) mod n +1,R = (r0-1 + x ) mod n +1
while(M--)
{
l=read();r=read();
l=(l-1+x)%N+1,r=(r-1+x)%N+1;
if(l>r) std::swap(l,r);
// printf("%d %d\n",l,r);
x=query(l,r);
printf("%d\n",x);
}
return 0;
}
那么,分块还有什么用呢
其实,有些时候,我们可以通过只维护块的信息来省省空间
比如求多维偏序的问题,我们考虑对每一维分别排序,然后分块,每个块维护一个下标集合表示该维比这个块小的所有下标
那么按照分块的老套路,对于每个数查询该维比自己小的数的集合是\(O(n \sqrt n)\)的
剩下的就是求每个维的集合的并了?如果你回bitset,它可以做到 \(O(n^2 k/32)\) k是维度数量。。。
Blog来自PaperCloud,未经允许,请勿转载,TKS!
luogu P4168 蒲公英+ 分块学习笔记的更多相关文章
- 分块学习笔记qwq
我没想到居然就学到分块了...哇我还一直觉得分块听起来挺牛逼的一直想学的来着qwq(其实之前好像vjudge上有道题是用分块做的?等下放链接qwq 所以想着就写个学习笔记趴qwq 首先知道分块的时间复 ...
- CH 4401/Luogu 4168 - 蒲公英 - [分块]
题目链接:传送门 题目链接:https://www.luogu.org/problemnew/show/P4168 题解: 经典的在线求区间众数的问题,由于区间众数不满足区间可加性,所以考虑分块,假设 ...
- 洛谷P4168 蒲公英 分块处理区间众数模板
题面. 许久以前我还不怎么去机房的时候,一位大佬好像一直在做这道题,他称这道题目为"大分块". 其实这道题目的思想不只可以用于处理区间众数,还可以处理很多区间数值相关问题. 让我们 ...
- 整除分块学习笔记+[CQOI2007]余数求和(洛谷P2261,BZOJ1257)
上模板题例题: [CQOI2007]余数求和 洛谷 BZOJ 题目大意:求 $\sum^n_{i=1}k\ mod\ i$ 的值. 等等……这题就学了三天C++的都会吧? $1\leq n,k\leq ...
- 莫比乌斯反演&整除分块学习笔记
整除分块 用于计算$\sum_{i=1}^n f(\lfloor{n/i} \rfloor)*i$之类的函数 整除的话其实很多函数值是一样的,对于每一块一样的商集中处理即可 若一个商的左边界为l,则右 ...
- 莫队学习笔记(未完成QAQ
似乎之前讲评vjudge上的这题的时候提到过?但是并没有落实(...我发现我还有好多好多没落实?vjudge上的题目还没搞,然后之前考试的题目也都还没总结?天哪我哭了QAQ 然后这三道题我都是通过一道 ...
- 再探快速傅里叶变换(FFT)学习笔记(其三)(循环卷积的Bluestein算法+分治FFT+FFT的优化+任意模数NTT)
再探快速傅里叶变换(FFT)学习笔记(其三)(循环卷积的Bluestein算法+分治FFT+FFT的优化+任意模数NTT) 目录 再探快速傅里叶变换(FFT)学习笔记(其三)(循环卷积的Blueste ...
- Hadoop学习笔记(7) ——高级编程
Hadoop学习笔记(7) ——高级编程 从前面的学习中,我们了解到了MapReduce整个过程需要经过以下几个步骤: 1.输入(input):将输入数据分成一个个split,并将split进一步拆成 ...
- osgEarth学习笔记(转载)
osgEarth学习笔记1. 通过earth文件创建图层时,可以指定多个影像数据源和多个高程数据源,数据源的顺序决定渲染顺序,在earth文件中处于最前的在渲染时处于最底层渲染:所以如果 ...
随机推荐
- java influx DB工具类
配置 application-properties: spring.influxdb.url=${influxdb_host:127.0.0.1} spring.influxdb.port=${inf ...
- J.U.C之AQS:CLH同步队列
此篇博客所有源码均来自JDK 1.8 在上篇博客[死磕Java并发]—–J.U.C之AQS:AQS简介中提到了AQS内部维护着一个FIFO队列,该队列就是CLH同步队列. CLH同步队列是一个FIFO ...
- 【转载】 C#中PadRight函数以特定字符在字符串结尾补足位数
在C#开发过程中字符串String类处理过程中,有时字符串长度不够时,需要在右侧侧指定特定的字符来补足字符串长度,此时可以使用String类下的PadRight方法对字符串结尾按特定的字符补足位数.M ...
- UI5-技术篇-事务Tcode
1.LPD_CUST 快速启动板概览 2./N/UI2/FLPD_CONF 创建目录与组(全部客户端) 3./N/UI2/FLPD_CUST 创建目录与组(当前客户端) 4./N/UI2/FLP 编辑 ...
- Git Git 已被其他开发删除的远程分支,本地依旧显示,如何删除?
- Vue框架之基础知识
在没有学习基础知识之前,我们需要下载vue的js文件,在使用vue语法之前引包 <script src='./vue.js'></script> 一.模板语法 模板语法是一种可 ...
- Java--8--新特性--Lambda
java9 都出来了,我才开始接触到java8的新特性,有点脱节啊.. Lambda是一个匿名函数,可以理解为一段可以传递的代码,将代码像数据一样传递,下面是一个小例子. public class E ...
- 2. 软件有很多种,也有各种分类办法: ShrinkWrap (在包装盒子里面的软件,软件在CD/DVD上); Web APP (基于网页的软件); Internal Software (企业或学校或某组织内部的软件); Games (游戏); Mobile Apps (手机应用); Operating Systems (操作系统); Tools
选取对你最相关的一类软件, 请回答:(web app) 1) 此类软件是什么时候开始出现的, 这些软件是怎么说服你(陌生人)成为他们的用户的? 他们的目标都是盈利么? 他们的目标都是赚取用户 ...
- Redis 从入门到放弃
Redis 从入门到放弃 http://www.iocoder.cn/Fight/Redis-went-from-getting-started-to-quitting/
- oj.zstu 4421交税(合数分解成素数)
题目 题意:T组,每一组输入一个数X, 求X最少能分成几个素数的和,输出. 思路: 对于一个大于2的偶数,由哥德巴赫猜想,一定能分成2个素数. 对于一个奇数来说,一定能分成2个或者3个素数之和.如果 ...