【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 ...
随机推荐
- 【译】Exception Helper – Rethrown Exceptions
是否曾经在异步编程时引发过异常?因为调试器没有显示异常发生的位置而感到沮丧?或者在查看具有内部异常的异常时感到沮丧?调试器不容易显示该异常来自何处.从 Visual Studio 2019 16.5 ...
- 实战SpringCloud通用请求字段拦截处理
背景 以SpringCloud构建的微服务系统为例,使用前后端分离的架构,每个系统都会提供一些通用的请求参数,例如移动端的系统版本信息.IMEI信息,Web端的IP信息,浏览器版本信息等,这些参数可能 ...
- Report.Net 本地数据库、WebService、Socket报表
本地.服务器的Access.Sql报表编辑.预览.打印. 可自定义预览界面,可方便嵌入到你的程序中去,提供接口函数,如有需要可自行添加接口. 预览采用单双面方式,因为如果页面过多,预览不能全部加载,所 ...
- DVWA学习记录 PartⅢ
CSRF 1. 题目 CSRF,全称Cross-site request forgery,翻译过来就是跨站请求伪造,是指利用受害者尚未失效的身份认证信息(cookie.会话等),诱骗其点击恶意链接或者 ...
- Python-字符串内容检测
str.isnumeric():检测字符串是否只由数字组成 str.isalpha():检测字符串是否只由字母组成 str.islower():检测字符串中所有的字母是否都为小写 str.isuppe ...
- 数据分析04 /基于pandas的DateFrame进行股票分析、双均线策略制定
数据分析04 /基于pandas的DateFrame进行股票分析.双均线策略制定 目录 数据分析04 /基于pandas的DateFrame进行股票分析.双均线策略制定 需求1:对茅台股票分析 需求2 ...
- python 生成器(五):生成器实例(一)创建数据处理管道
问题 你想以数据管道(类似Unix管道)的方式迭代处理数据. 比如,你有个大量的数据需要处理,但是不能将它们一次性放入内存中. 解决方案 生成器函数是一个实现管道机制的好办法. 为了演示,假定你要处理 ...
- Python: 如何判断远程服务器上Excel文件是否被人打开
最近工作中需要去判断远程服务器上的某个Excel文件是否被打开,如果被人打开,则等待,如果没人打开使用,则去填写数据进Excel文件. 开始想的很简单,和其他语言一样,比如C#,打开文件,如果报错说明 ...
- project facet java 1.8 is not supported解决办法
Right click on project -> Properties -> Search for Project Facets -> Java (Version)
- 网络流(dinic算法)
洛谷p3376 https://www.luogu.com.cn/problem/P3376 #include <iostream> #include <cstdio> #in ...