【BZOJ2724】蒲公英 题解(分块+区间众数)
题目大意:给定一段长度为$n$的序列和$m$次询问,每次询问区间$[l,r]$内的最小的众数。$n\leq 40000,a_i\leq 10^9$
-----------------------------
因为$a_i\leq 10^9$,显然不能开那么大的数组。所以要离散化。对于离散化后的数组,我们维护两个值$sum[i][j]$和$p[i][j]$。$sum[i][j]$表示前$i$个块中$j$出现的次数,这个$O(n \sqrt n)$暴力枚举就好。$p[i][j]$表示块$i$到$j$的众数,这个只需开一个桶维护,然后$O(\sqrt n \sqrt n \sqrt n)$暴力枚举就好。
对于查询,我们仍然暴力把区间$[l,r]$中边边角角的部分暴力求出来,对于整块我们用之前维护的$sum$和$p$即可。
其实就是一个大模拟……细节有点小多。不会真的有人连敲代码都不会吧
代码(有些细节的地方有注释):
#include<bits/stdc++.h>
using namespace std;
const int maxn=;
int n,m,block,tot,sum[][maxn];
int last,pre[maxn],tmpnum[maxn],bucket[maxn],vis[maxn];
struct Node
{
int id,val,se;//id编号,val值,se离散化后的值
}a[];
struct node
{
int num,s;
}p[][];
inline int read()
{
int x=,f=;char ch=getchar();
while(!isdigit(ch)){if (ch=='-') f=-;ch=getchar();}
while(isdigit(ch)){x=x*+ch-'';ch=getchar();}
return x*f;
}
bool cmp1(Node a,Node b){return a.val<b.val;}//离散化排序
bool cmp2(Node a,Node b){return a.id<b.id;}
int getpos(int x)//不用维护每个区间的左右端点了,一个函数搞定
{
int pos=x/block;
if (x%block) pos++;
return pos;
}
inline void build()
{
for (int i=;i<=tot;i++)
{
memset(bucket,,sizeof(bucket));node tmp;//注意清空桶
tmp.s=tmp.num=;
for (int j=i;j<=tot;j++)
{
for (int k=(j-)*block+;k<=min(n,j*block);k++)//预处理
{
bucket[a[k].se]++;
if (bucket[a[k].se]>tmp.s)
{
tmp.s=bucket[a[k].se];
tmp.num=a[k].se;
}
else if (bucket[a[k].se]==tmp.s) tmp.num=min(tmp.num,a[k].se);
}
p[i][j]=tmp;
}
}
for (int i=;i<=tot;i++){//预处理
for (int j=;j<=n;j++) sum[i][a[j].se]=sum[i-][a[j].se];
for (int j=(i-)*block+;j<=min(n,i*block);j++) sum[i][a[j].se]++;
}
}
inline void query(int l,int r)
{
int posl=getpos(l),posr=getpos(r);
if (posr-posl<=)//如果区间范围较小直接暴力枚举即可
{
int ans=;
for (int i=l;i<=r;i++) tmpnum[a[i].se]=;//开一个桶,注意清空
for (int i=l;i<=r;i++){
tmpnum[a[i].se]++;
if (tmpnum[a[i].se]>tmpnum[ans]) ans=a[i].se;
else if (tmpnum[a[i].se]==tmpnum[ans]) ans=min(ans,a[i].se);
}
printf("%d\n",last=pre[ans]);
return;
}
int ans=p[posl+][posr-].num,maxsum=,maxnum;//用预处理的p数组维护ans
vis[ans]=;tmpnum[ans]=;
////////////暴力把边边角角统计出来//////////////
for (int i=l;i<=min(n,posl*block);i++) tmpnum[a[i].se]=,vis[a[i].se]=;
for (int i=(posr-)*block+;i<=r;i++) tmpnum[a[i].se]=,vis[a[i].se]=;
for (int i=l;i<=min(n,posl*block);i++) tmpnum[a[i].se]++;
for (int i=(posr-)*block+;i<=r;i++) tmpnum[a[i].se]++;
for (int i=l;i<=min(n,posl*block);i++){
if (vis[a[i].se]) continue;
vis[a[i].se]=;
int summ=tmpnum[a[i].se]+sum[posr-][a[i].se]-sum[posl][a[i].se];//个数
if (summ>maxsum) maxsum=summ,maxnum=a[i].se;
else if (maxsum==summ) maxnum=min(maxnum,a[i].se);
}
for (int i=(posr-)*block+;i<=r;i++){
if (vis[a[i].se]) continue;
vis[a[i].se]=;
int summ=tmpnum[a[i].se]+sum[posr-][a[i].se]-sum[posl][a[i].se];//个数
if (summ>maxsum) maxsum=summ,maxnum=a[i].se;
else if (maxsum==summ) maxnum=min(maxnum,a[i].se);
}
///////////////////////////////////////////////
if (maxsum>tmpnum[ans]+p[posl+][posr-].s) ans=maxnum;
else if (maxsum==tmpnum[ans]+p[posl+][posr-].s) ans=min(ans,maxnum);
printf("%d\n",last=pre[ans]);
}
int main()
{
n=read(),m=read();block=sqrt(n);
tot=(n+block-)/block;
for (int i=;i<=n;i++) a[i].val=read(),a[i].id=i;
sort(a+,a+n+,cmp1);a[].val=-;
for (int i=;i<=n;i++)//离散化
{
a[i].se=a[i-].se;
if (a[i].val!=a[i-].val) a[i].se++;
pre[a[i].se]=a[i].val;
}
sort(a+,a+n+,cmp2);
build();
for (int i=;i<=m;i++)
{
int l=read(),r=read();
l=(l+last-)%n+;
r=(r+last-)%n+;
if (l>r) swap(l,r);
query(l,r);
}
return ;
}
【BZOJ2724】蒲公英 题解(分块+区间众数)的更多相关文章
- 蒲公英(bzoj2724)(分块+区间众数)
Input Output Sample Input 6 3 1 2 3 2 1 2 1 5 3 6 1 5 Sample Output 1 2 1 HINT \(n <= 40000\),$ m ...
- BZOJ2724 蒲公英 【分块】
BZOJ2724 蒲公英 题目背景 亲爱的哥哥: 你在那个城市里面过得好吗? 我在家里面最近很开心呢.昨天晚上奶奶给我讲了那个叫「绝望」的大坏蛋的故事的说!它把人们的房子和田地搞坏,还有好多小朋友也被 ...
- bzoj2724: [Violet 6]蒲公英 分块 区间众数 论algorithm与vector的正确打开方式
这个,要处理各个数的话得先离散,我用的桶. 我们先把每个块里的和每个块区间的众数找出来,那么在查询的时候,可能成为[l,r]区间的众数的数只有中间区间的众数和两边的数. 证明:若不是这里的数连区间的众 ...
- BZOJ 2724: [Violet 6]蒲公英 [分块 区间众数]
传送门 题面太美不忍不放 分块分块 这种题的一个特点是只有查询,通常需要预处理:加入修改的话需要暴力重构预处理 预处理$f[i][j]$为第i块到第j块的众数,显然$f[i][j]=max{f[i][ ...
- LOJ6285 数列分块入门9(分块 区间众数)题解
题意:给出区间内的最小众数 思路:分块,离散化每个数,开vector记录每个数p出现的位置,这样就能二分出L,R以内p的个数了.众数有一个性质,用mode(a)表示集合a的众数,那么mode(a∪b) ...
- 洛谷P4168 蒲公英 分块处理区间众数模板
题面. 许久以前我还不怎么去机房的时候,一位大佬好像一直在做这道题,他称这道题目为"大分块". 其实这道题目的思想不只可以用于处理区间众数,还可以处理很多区间数值相关问题. 让我们 ...
- 【BZOJ2724】蒲公英(分块)
[BZOJ2724]蒲公英(分块) 题面 洛谷 谴责权限题的行为 题解 分块什么的都不会,根本就没写过几次. 复杂度根本不会分析,吓得我赶快来练练. 这题要求的是区间众数,显然没有什么很好的主席树之类 ...
- BZOJ2724 [Violet]蒲公英(分块)
区间众数.分块,预处理任意两块间所有数的众数,和每块中所有数的出现次数的前缀和.查询时对不是整块的部分暴力,显然只有这里出现的数可能更新答案.于是可以优美地做到O(n√n). #include< ...
- 【BZOJ 2724】 2724: [Violet 6]蒲公英 (区间众数不带修改版本)
2724: [Violet 6]蒲公英 Time Limit: 40 Sec Memory Limit: 512 MBSubmit: 1908 Solved: 678 Description In ...
随机推荐
- day05总结
""" echo "了不起的 [陈少] " 输出结果: 了不起的陈少! ! ! """ ""& ...
- class文件的基本结构及proxy源码分析二
前文地址:https://www.cnblogs.com/tera/p/13267630.html 本系列文章主要是博主在学习spring aop的过程中了解到其使用了java动态代理,本着究根问底的 ...
- electron设置window系统托盘
electron设置托盘 // 设置系统托盘 const setAppTray = () => { // 托盘对象 var appTray = null // 系统托盘右键菜单 var tray ...
- 使用eval将字符串转化成字典时报name 'null' is not defined错误解决办法
在接口测试过程中,为了取值将形如字典形式的字符串使用eval()方法转化成字典方便取值 str={"code":100,"num":1,"data&q ...
- 数据可视化之powerBI技巧(十)利用度量值,轻松进行动态指标分析
在一个图表中,可以将多项指标数据放进去同时显示,如果不想同时显示在一起,可以根据需要动态显示数据吗?在 PowerBI 中当然是可以的. 下面就看看如何利用度量值进行动态分析. 假如要分析的指标有销售 ...
- 数据可视化之DAX篇(九) 关于DAX中的VAR,你应该避免的一个常见错误
https://zhuanlan.zhihu.com/p/67803111 本文源于微博上一位朋友的问题,在计算同比增长率时,以下两种DAX代码有什么不同? -------------------- ...
- 如何用 Python 做自动化测试【进阶必看】
一.Selenium 环境部署 1. window 环境部署 1.1 当前环境Win10 64 位系统:Python3.6.2(官方已经更新到了 3.6.4) 官方下载地址:https://www.p ...
- 获取字符串指定字符的第n次出现位置
create function uf_findx (@text nvarchar(max),@find_x varchar(200),@find_n int)returns intasbegin -- ...
- JAVA集合二:HashMap和Hashtable
参考链接: HOW2J.CN HashMap HashMap实现了JAVA的Map接口,类似于C++的STL框架的Map,是存储键值对的数据结构.键(key)是唯一的,但值(value)可以重复,如果 ...
- sqlserver安装出现找不到数据库引擎错误
sqlserver安装出现找不到数据库引擎错误 问题的解决 第一次安装SQL server,发现它较于Oracle,都有安装卸载十分麻烦的特点.刚开始安装,就让我频繁遇到这个“找不到数据库引擎”的错误 ...