题目链接

题目大意:给定一段长度为$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】蒲公英 题解(分块+区间众数)的更多相关文章

  1. 蒲公英(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 ...

  2. BZOJ2724 蒲公英 【分块】

    BZOJ2724 蒲公英 题目背景 亲爱的哥哥: 你在那个城市里面过得好吗? 我在家里面最近很开心呢.昨天晚上奶奶给我讲了那个叫「绝望」的大坏蛋的故事的说!它把人们的房子和田地搞坏,还有好多小朋友也被 ...

  3. bzoj2724: [Violet 6]蒲公英 分块 区间众数 论algorithm与vector的正确打开方式

    这个,要处理各个数的话得先离散,我用的桶. 我们先把每个块里的和每个块区间的众数找出来,那么在查询的时候,可能成为[l,r]区间的众数的数只有中间区间的众数和两边的数. 证明:若不是这里的数连区间的众 ...

  4. BZOJ 2724: [Violet 6]蒲公英 [分块 区间众数]

    传送门 题面太美不忍不放 分块分块 这种题的一个特点是只有查询,通常需要预处理:加入修改的话需要暴力重构预处理 预处理$f[i][j]$为第i块到第j块的众数,显然$f[i][j]=max{f[i][ ...

  5. LOJ6285 数列分块入门9(分块 区间众数)题解

    题意:给出区间内的最小众数 思路:分块,离散化每个数,开vector记录每个数p出现的位置,这样就能二分出L,R以内p的个数了.众数有一个性质,用mode(a)表示集合a的众数,那么mode(a∪b) ...

  6. 洛谷P4168 蒲公英 分块处理区间众数模板

    题面. 许久以前我还不怎么去机房的时候,一位大佬好像一直在做这道题,他称这道题目为"大分块". 其实这道题目的思想不只可以用于处理区间众数,还可以处理很多区间数值相关问题. 让我们 ...

  7. 【BZOJ2724】蒲公英(分块)

    [BZOJ2724]蒲公英(分块) 题面 洛谷 谴责权限题的行为 题解 分块什么的都不会,根本就没写过几次. 复杂度根本不会分析,吓得我赶快来练练. 这题要求的是区间众数,显然没有什么很好的主席树之类 ...

  8. BZOJ2724 [Violet]蒲公英(分块)

    区间众数.分块,预处理任意两块间所有数的众数,和每块中所有数的出现次数的前缀和.查询时对不是整块的部分暴力,显然只有这里出现的数可能更新答案.于是可以优美地做到O(n√n). #include< ...

  9. 【BZOJ 2724】 2724: [Violet 6]蒲公英 (区间众数不带修改版本)

    2724: [Violet 6]蒲公英 Time Limit: 40 Sec  Memory Limit: 512 MBSubmit: 1908  Solved: 678 Description In ...

随机推荐

  1. shell专题(七):流程控制(重点)

    7.1 if 判断 1.基本语法 if [ 条件判断式 ];then 程序 fi 或者 if [ 条件判断式 ] then 程序 fi 注意事项: (1)[ 条件判断式 ],中括号和条件判断式之间必须 ...

  2. java 面向对象(七):类结构 方法(四)递归方法

    1.定义:递归方法:一个方法体内调用它自身.2.如何理解递归方法?> 方法递归包含了一种隐式的循环,它会重复执行某段代码,但这种重复执行无须循环控制.> 递归一定要向已知方向递归,否则这种 ...

  3. Dresdon简介

    很久没有写文章了.这几年经历了很多事情:离开VMware的不舍,拿到融资的开心,重回VMware的亲切,以及不再争强好胜,只做自己喜欢事情的平和. 可以说,我是幸运的:我这一辈子都在选择,而不是被迫接 ...

  4. 数字孪生,数据驱动下的北京 CBD 智能楼宇三维可视化系统

    前言 楼宇作为建筑基础设施的主体,为人们提供着重要的生存空间.随着物联网.人工智能概念的兴起以及智慧城市如火如荼的开展,智能楼宇的重要性越发突显. 随着城市现代化建设的发展,建筑的智能化,特别是公用建 ...

  5. STL源码剖析:配置器

    作用:对内存的管理 接口:申请和释放 内容: 几个全局函数 一级配置器 二级配置器 准备知识 POD是什么: Plain Old Data简称POD,表示传统的C语言类型:与POD类型对应的是非POD ...

  6. 微信小程序入门从这里出发(登录注册、开发工具、文件及结构介绍)

    (一) 准备工作 (1) 登录注册 注册账号:这就不谈了,只需要注意使用一个全新的邮箱,别之前注册过公众号小程序等就可以了 https://mp.weixin.qq.com/wxopen/waregi ...

  7. 【mysql】- 事务隔离级别和MVCC篇

    概念 术语 脏写( Dirty Write ): 如果一个事务修改了另一个未提交事务修改过的数据,那就意味着发了脏写 脏读( Dirty Read ) : 如果一个事务读到了另一个未提交事务修改过的数 ...

  8. DC-1靶机实战和分析

    前言 我们都知道,对靶机的渗透,可以宽阔自己的解题思路,练习并熟悉相关操作命令,提高自己的能力.下面我就对Vulnhub的DC-1靶机进行渗透,靶机设置了5个flag,咱们依次找到它.并通过图文形式讲 ...

  9. vue图片上传的简单组件

    <template> <div class="rili" id="rili"> <div class="updel&qu ...

  10. Docker 概念-2

    Docker 是什么? 说了这么多, Docker 到底是个什么东西呢?我们在理解 Docker 之前,首先得先区分清楚两个概念,容器和虚拟机. 可能很多读者朋友都用过虚拟机,而对容器这个概念比较的陌 ...