[Violet]蒲公英 分块
发现写算法专题老是写不动,,,,
所以就先把我在luogu上的题解搬过来吧!
题目大意:查询区间众数,无修改,强制在线
乍一看是一道恐怖的题,仔细一看发现并没有那么难;
大致思路是这样的,首先我们要充分发挥分块暴力大法好的精神
先暴力预处理出每个块内每种蒲公英的个数,
然后求出对每个块而言的前缀和,
于是这样我们就可以区间查询任意两个块之间每种蒲公英的数量了
然后我们预处理出任意两个块之间的众数
最后对于每组询问,我们先找到夹在它们中间的块,
如果这个两个块r-l<=1,那么我们暴力求众数
为什么? 因为不这样的话,万一x,y在一个快,那么r可能会比l小,要特判
如果x,y隔得很近,同样有各种奇奇怪怪的情况要做特判,
那既然这么麻烦,我们不如直接暴力搞是吧。
如果两个块相差超过了1,那么我们先取出中间块的众数,作为我们的answer,然后对旁边两个块暴力处理众数(此处注意判断时要加上中间的蒲公英)。
最后我们就得到了答案,
但是注意到ai的范围很大,所以我们需要离散化。
并且由于数量相同时要优先编号小的,于是我们处理众数的时候要多加这个判断
基本就是这样了。。。
表示本蒟蒻一A过了还是很开心的(^▽^)(虽然说第一次交没删调试结果too many or too few lines 了,但是去掉调试就过了,也可以算是一A嘛是吧)
下面代码:
#include<bits/stdc++.h>
using namespace std;
#define R register int
#define AC 40100
#define ac 210
#define D printf("line in %d\n",__LINE__);
int block,n,m,answer,tot;
int s[AC];
struct abc{
int num,w,x;
}b[AC];//原数列+离散化后数组
int sum[ac][AC];//每种数字块内前缀和
int ans[ac][ac];//任意两块之间的众数
int belong[AC];//所属块
int color[AC]; inline int read()
{
int x=;char c=getchar();
while(c>'' || c<'') c=getchar();
while(c>='' && c<='') x=x*+c-'',c=getchar();
return x;
} bool cmp1(abc a,abc b)
{
return a.w < b.w;
} bool cmp2(abc a,abc b)
{
return a.num < b.num;
} void search(int x,int y)
{
// printf("%d %d\n",x,y);
int l=x/block + ,r=y/block - ;//取出中间块
if(r - l <= )//如果x,y相差很小,那么暴力统计
{
answer=;
for(R i=x;i<=y;i++)
if((++color[b[i].x] > color[answer]) || (color[b[i].x] == color[answer] && b[i].x < answer)) answer=b[i].x;
for(R i=x;i<=y;i++)
--color[b[i].x];
printf("%d\n",s[answer]);
return ;
}
else//不然的话
{
int ll=l * block - ,rr=(r+) * block;
answer=ans[l][r];
for(R i=x;i<=ll;i++)
{
++color[b[i].x];
if(color[b[i].x] + sum[r][b[i].x] - sum[l-][b[i].x] > color[answer] + sum[r][answer] - sum[l-][answer]) answer=b[i].x;
else if(color[b[i].x] + sum[r][b[i].x] - sum[l-][b[i].x] == color[answer] + sum[r][answer] - sum[l-][answer] && b[i].x < answer) answer=b[i].x;//编号小也要优先,因为一行写不下,为了美观,,,就用else吧,不然就用||了
}
for(R i=rr;i<=y;i++)
{
++color[b[i].x];
if(color[b[i].x] + sum[r][b[i].x] - sum[l-][b[i].x] > color[answer] + sum[r][answer] - sum[l-][answer]) answer=b[i].x;
else if(color[b[i].x] + sum[r][b[i].x] - sum[l-][b[i].x] == color[answer] + sum[r][answer] - sum[l-][answer] && b[i].x < answer) answer=b[i].x;
}
for(R i=x;i<=ll;i++) --color[b[i].x];
for(R i=rr;i<=y;i++) --color[b[i].x];
printf("%d\n",s[answer]);
return ;
}
} void pre()//读入
{
n=read(),m=read();
block=sqrt(n);
for(R i=;i<=n;i++) b[i].w=read(),b[i].num=i;
sort(b+,b+n+,cmp1);
for(R i=;i<=n;i++)
{
if(b[i].w != b[i-].w)
{
s[++tot]=b[i].w;//存下对应新编号的对应真实编号
b[i].x=tot;
}
else b[i].x=b[i-].x;//离散化
}
sort(b+,b+n+,cmp2);
} void getsum()
{//注意0也被分在块0中
for(R i=;i<=n;i++)
{
belong[i]=i/block;
sum[belong[i]][b[i].x]++;
}
for(R i=;i<=belong[n];i++)
for(R j=;j<=tot;j++)
sum[i][j]+=sum[i-][j];
} void getans()
{
for(R i=;i<=belong[n];i++)
{
int be=i * block,now=;
if(!be) be=;//这里和作诗不同,因为这里的now要参与比较了,而不是单纯的统计,而now初始值为0,所以color[0]不能被修改
for(R j=be;j<=n;j++)
{
if((++color[b[j].x] > color[now]) || (color[b[j].x] == color[now] && b[j].x < now)) now=b[j].x;//更新ans
ans[i][belong[j]]=now;//存下新ans
}
for(R j=be;j<=n;j++) --color[b[j].x];//暴力撤销
}
/*for(R i=0;i<=belong[n];i++)
{
for(R j=i;j<=belong[n];j++)
printf("%d ",ans[i][j]);
printf("\n");
}*/
} void work()//预处理出前缀和和众数
{
int a,b;
for(R i=;i<=m;i++)
{
a=(read() + s[answer] -) % n + ,b=(read() + s[answer] - ) % n + ;//获取询问
if(a < b) search(a,b);
else search(b,a);//因为经过了运算,所以大小顺序就可能改变了
}
} int main()
{
// freopen("in.in","r",stdin);
pre();
getsum();
getans();
work();
// fclose(stdin);
return ;
}
[Violet]蒲公英 分块的更多相关文章
- BZOJ2724 [Violet]蒲公英 分块
题目描述 经典区间众数题目 然而是权限题,所以题目链接放Luogu的 题解 因为太菜所以只会$O(n*\sqrt{n}+n*\sqrt{n}*log(n))$的做法 就是那种要用二分的,并不会clj那 ...
- Luogu P4168 [Violet]蒲公英 分块
这道题算是好好写了.写了三种方法. 有一个好像是$qwq$$N\sqrt(N)$的方法,,但是恳请大佬们帮我看看为什么这么慢$qwq$(后面的第三种) 注:$pos[i]$表示$i$属于第$pos[i ...
- 洛谷 P4168 [Violet]蒲公英 解题报告
P4168 [Violet]蒲公英 题目背景 亲爱的哥哥: 你在那个城市里面过得好吗? 我在家里面最近很开心呢.昨天晚上奶奶给我讲了那个叫「绝望」的大坏蛋的故事的说!它把人们的房子和田地搞坏,还有好多 ...
- BZOJ 2724: [Violet 6]蒲公英( 分块 )
虽然AC了但是时间惨不忍睹...不科学....怎么会那么慢呢... 无修改的区间众数..分块, 预处理出Mode[i][j]表示第i块到第j块的众数, sum[i][j]表示前i块j出现次数(前缀和, ...
- 【BZOJ2724】[Violet 6]蒲公英 分块+二分
[BZOJ2724][Violet 6]蒲公英 Description Input 修正一下 l = (l_0 + x - 1) mod n + 1, r = (r_0 + x - 1) mod n ...
- BZOJ 2724: [Violet 6]蒲公英 [分块 区间众数]
传送门 题面太美不忍不放 分块分块 这种题的一个特点是只有查询,通常需要预处理:加入修改的话需要暴力重构预处理 预处理$f[i][j]$为第i块到第j块的众数,显然$f[i][j]=max{f[i][ ...
- BZOJ2724 [Violet 6]蒲公英 分块
原文链接https://www.cnblogs.com/zhouzhendong/p/BZOJ2724.html 题目传送门 - BZOJ2724 题意 求区间最小众数,强制在线. $n$ 个数,$m ...
- BZOJ2724 [Violet]蒲公英(分块)
区间众数.分块,预处理任意两块间所有数的众数,和每块中所有数的出现次数的前缀和.查询时对不是整块的部分暴力,显然只有这里出现的数可能更新答案.于是可以优美地做到O(n√n). #include< ...
- p4168 [Violet]蒲公英(分块)
区间众数的重题 和数列分块入门9双倍经验还是挺好的 然后开O2水过 好像有不带log的写法啊 之后在补就是咕咕咕 // luogu-judger-enable-o2 #include <cstd ...
随机推荐
- 解决 idea template jsp模板中使用自定义路径 模板不显示问题
${} 是一个模板中的关键字,所以建立时需要用 \ 注释即可正常显示 ${APP_PATH}
- 【JUC源码解析】LinkedBlockingQueue
简介 一个基于链表的阻塞队列,FIFO的顺序,head指向的元素等待时间最长,tail指向的元素等待时间最短,新元素从队列尾部添加,检索元素从队列头部开始,队列的容量,默认是Integer#MAX_V ...
- 一次性搞定Session
相信很多人遇到过同一个浏览器会出现Session覆盖问题.今天主要针对Session覆盖问题来看看Session是如何工作的.那么先看一张简单的图说明一下 上面的图大致的说明Session工作简单创建 ...
- 如何下载YouTube 60fps视频
YouTube上面不仅支持分辨率为4K和8K的视频,同时也开启了对60fps视频的支持.60帧的视频广泛用于游戏和体育视频中,使视频看起来更加流畅和细腻.对游戏玩家来说,YouTube对60fps支持 ...
- Configure,Makefile.am, Makefile.in, Makefile文件
一 软件安装关于 makefile文件问题 如果拿到的工程文件中,没有Makefile文件,而只有configure.in和Makefile.am文件,我们是不能够直接进行编译的,必须根据config ...
- Python列表推导式和嵌套的列表推导式
列表推导式提供了一个更简单的创建列表的方法.常见的用法是把某种操作应用于序列或可迭代对象的每个元素上,然后使用其结果来创建列表,或者通过满足某些特定条件元素来创建子序列. 例如,假设我们想创建一个平方 ...
- Node开发项目管理工具 Grunt 对比 Gulp
转自Gulp vs Grunt 1. Grunt -> Gulp 早些年提到构建工具,难免会让人联想到历史比较悠久的Make,Ant,以及后来为了更方便的构建结构类似的Java项目而出现的Mav ...
- Spring学习(2):面向接口编程思想
一. 引言 Spring核心的IOC的实体用了面向接口编程思想,所以有必要了解下.简单来说的话,Spring就是一个轻量级的控制反转(IOC)和面向切面(AOP)的容器框架. 接口的定义的概念:泛指实 ...
- python循环结构
while循环 while 条件表达式: 语句块 while语句的条件表达式是循环条件,常用的是关系表达式或者逻辑表达式,语句块是循环执行的语句. n=1 p=1 num=int(input(&quo ...
- USACO 1.2.3 Name That Number 命名那个数字(打开文件)
Description 在威斯康辛州牛大农场经营者之中,都习惯于请会计部门用连续数字给母牛打上烙印.但是,母牛用手机时并没感到这个系统的便利,它们更喜欢用它们喜欢的名字来呼叫它们的同伴,而不是用像这个 ...