【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 ...
随机推荐
- Java 项目创建 -- 统一结果处理、统一异常处理、统一日志处理
一.IDEA 插件使用 1.说明 此处使用 SpringBoot 2.2.6 .JDK 1.8 .mysql 8.0.18 作为演示. 使用 IDEA 作为开发工具. 2.IDEA 插件 -- Lom ...
- docker自动化部署前端项目实战一
docker自动化部署前端项目实战一 本文适用于个人项目,如博客.静态文档,不涉及后台数据交互,以部署文档为例. 思路 利用服务器node脚本,监听github仓库webhook push事件触发po ...
- day39 进程
目录 一.进程对象的其他方法 二.僵尸进程与孤儿进程(了解) 1 僵尸进程 2 孤儿进程 三.守护进程 四.互斥锁 五.进程间通信 六.IPC机制 七.生产者消费者模型 八.线程理论 一.进程对象的其 ...
- SQL批量插入数据【万级】
1.每4000条插入一次 for (int i = 0; i < dt.Rows.Count; i++) { IsTBProductForStockInfo model = new IsTBPr ...
- java8的parallelStream提升数倍查询效率
业务场景 在很多项目中,都有类似数据汇总的业务场景,查询今日注册会员数,在线会员数,订单总金额,支出总金额等...这些业务通常都不是存在同一张表中,我们需要依次查询出来然后封装成所需要的对象返回给前端 ...
- three.js 曲线
上几篇说了three.js的曲线,这篇来郭先生来说说three.js曲线,在线案例点击郭先生的博客查看. 1. 了解three.js曲线 之前已经说了一些three.js的几何体,这篇说一说three ...
- com.aliyun.openservices.shade.com.alibaba.fastjson.JSONException: exepct '[', but {, pos 1, line 1, column 2
报错原因:你放的是一个非List的对象 却想取一个List对象出来 package test; import java.text.SimpleDateFormat; import java.util. ...
- Cyber Security - Palo Alto Firewall Objects Addresses, Services, and Groups(3)
LDAP Authentication and Remote Users and Groups Create Remote User Objects and LDAP Integration: sam ...
- CentOS8.0 Docker Repository
一.硬件软件准备 1.2台服务器或者电脑(使用云服务器1.阿里云 2.百度云各一台) ,系统均为CentOS 8.0 2.分别安装Docker 3.测试镜像准备(准备的是 ...
- WYT的刷子
WYT的刷子 题目描述 WYT有一把巨大的刷子,刷子的宽度为M米,现在WYT要使用这把大刷子去粉刷有N列的栅栏(每列宽度都为1米:每列的高度单位也为米,由输入数据给出). 使用刷子的规则是: 与地面垂 ...