luogu4168蒲公英(区间众数)

给定n个数,m个区间询问,问每个询问中的众数是什么。

题面很漂亮,大家可以去看一下。

对于区间众数,由于区间的答案不能由子区间简单的找出来,所以似乎不能用树形结构。

用分块的话,设一个区间[x, y],里面包含的最大连续的块的左端点是l,右端点是r。那么显然,这个区间的众数要么是[l, r]的众数,要么是[x, l)和(r, y]中的任意数。所以可以用\(f[i][j]\)表示第i到j块的众数是什么,同时用\(s[i][x]\)表示前i个块中数x的出现次数。这样就可以做到\(n\sqrt{n}\)了。我的代码跑的算很快的。因为map没有sort快(废话)。

有一个很神的地方是f[i][j]只用保存一个值就行了,因为如果在第i个块到第j个块之间,还有数的出现次数和f[i][j]相同,那么它要超越f[i][j],必须满足在一侧的小区间中出现次数比f[i][j]多,所以它至少会在小区间中出现一次。

如果问题带修怎么办呢?还是可以用分块哟。由于我们要维护f[i][j]和s[i][j],只分\(n^{1/3}\)个块。对于某一个点上的修改,会牵动所有块。再维护cnt[i][j][k]表示i块到j块出现次数为k的数有几个即可。

#include <cmath>
#include <cctype>
#include <cstdio>
#include <algorithm>
using namespace std; const int maxn=4e4+5, sqrtm=2e2+5, INF=1e9;
int n, m, barlen, cntbar, a[maxn], bel[maxn], cnt[maxn];
int t[maxn], cntnum;
int s[sqrtm][maxn]; //前i个块x的出现次数
int f[sqrtm][sqrtm]; //第i到j块的众数是什么 void get(int &x){
x=0; char c; int flag=1;
for (c=getchar(); !isdigit(c); c=getchar());
for (x=c-48; c=getchar(), isdigit(c); )
x=x*10+c-48; x*=flag;
} int main(){
get(n); get(m); barlen=sqrt(n); cntbar=1;
for (int i=0; i<n; ++i){
get(a[i]); t[i]=a[i];
bel[i]=i/barlen;
if (i&&bel[i]!=bel[i-1]) ++cntbar;
}
sort(t, t+n); cntnum=unique(t, t+n)-t;
for (int i=0; i<n; ++i)
a[i]=lower_bound(t, t+cntnum, a[i])-t;
for (int i=0; i<n; ++i) ++s[bel[i]][a[i]];
for (int i=1; i<cntbar; ++i) //n^1.5
for (int j=0; j<n; ++j) s[i][j]+=s[i-1][j];
int maxm=0, mcnt, q1, q2, l, r, tmp;
for (int i=0; i<cntbar; ++i){ //n^1.5
for (int j=0; j<n; ++j) cnt[j]=0;
mcnt=0;
for (int j=i*barlen; j<n; ++j){
++cnt[a[j]];
if (cnt[a[j]]>mcnt||(cnt[a[j]]==mcnt&&a[j]<maxm))
mcnt=cnt[a[j]], maxm=a[j];
if (bel[j]!=bel[j+1]) f[i][bel[j]]=maxm;
}
}
maxm=0;
for (int iq=0; iq<m; ++iq){
get(q1); get(q2);
q1=(q1+maxm-1)%n; q2=(q2+maxm-1)%n; mcnt=0;
if (q1>q2) swap(q1, q2);
if (bel[q1]==bel[q2]){
maxm=INF;
for (int i=q1; i<=q2; ++i) cnt[a[i]]=0;
for (int i=q1; i<=q2; ++i){
++cnt[a[i]];
if (cnt[a[i]]>mcnt||(cnt[a[i]]==mcnt&&a[i]<maxm))
mcnt=cnt[a[i]], maxm=a[i];
}
printf("%d\n", maxm=t[maxm]);
continue;
}
l=bel[q1]+1; r=bel[q2]-1;
if (l<=r) maxm=f[l][r], mcnt=s[r][maxm]-s[l-1][maxm];
//cnt表示两边需要暴力查找的数的出现个数
for (int i=q1; i==q1||bel[i]==bel[i-1]; ++i) cnt[a[i]]=0;
for (int i=q2; i==q2||bel[i]==bel[i+1]; --i) cnt[a[i]]=0;
for (int i=q1; i==q1||bel[i]==bel[i-1]; ++i) ++cnt[a[i]];
for (int i=q2; i==q2||bel[i]==bel[i+1]; --i) ++cnt[a[i]];
for (int i=q1; i==q1||bel[i]==bel[i-1]; ++i){
tmp=cnt[a[i]]+s[r][a[i]]-s[l-1][a[i]];
if (tmp>mcnt||(tmp==mcnt&&a[i]<maxm))
mcnt=tmp, maxm=a[i];
}
for (int i=q2; i==q2||bel[i]==bel[i+1]; --i){
tmp=cnt[a[i]]+s[r][a[i]]-s[l-1][a[i]];
if (tmp>mcnt||(tmp==mcnt&&a[i]<maxm))
mcnt=tmp, maxm=a[i];
}
printf("%d\n", maxm=t[maxm]);
}
return 0;
}

luogu4168蒲公英(区间众数)的更多相关文章

  1. P4168 [Violet]蒲公英 区间众数

    $ \color{#0066ff}{ 题目描述 }$ 在乡下的小路旁种着许多蒲公英,而我们的问题正是与这些蒲公英有关. 为了简化起见,我们把所有的蒲公英看成一个长度为n的序列 \((a_1,a_2.. ...

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

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

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

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

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

  5. Luogu4168 蒲公英 (分块)

    题目传送门 题意 长度为n的序列,有m次询问,每次询问求\([l,r]\) 间的众数,如果有多个,输出最小的那个 \(n\le 4\times 10^4,m\le 5\times 10^5,a_i\l ...

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

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

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

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

  8. 【luogu1468】[Violet]蒲公英--求区间众数

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

  9. 【BZOJ2724】蒲公英 题解(分块+区间众数)

    题目链接 题目大意:给定一段长度为$n$的序列和$m$次询问,每次询问区间$[l,r]$内的最小的众数.$n\leq 40000,a_i\leq 10^9$ --------------------- ...

随机推荐

  1. pow,sqrt使用时需注意

    使用时注意类型,可见两者皆不可以用int 1.pow 函数声明: double pow (double base , double exponent); float pow (float base , ...

  2. Saiku_学习_02_Schema Workbench 开发mdx和模式文件

    一.前言 saiku的查询都是通过cube来进行的.因此每当我们要进行一次多维度查询时,都要先修改xml.上传.重启才能生效,不仅效率低,还不利于学习和理解MDX和模式文件. 通过 workbench ...

  3. UVA-11020(BST)

    题意: 给n个点,一个点(x,y)有优势时满足不存在点(fx,fy)使得fx<x,fy<=y或fx<=x,fy<y;问当前有多少个有优势点; 思路: 学习BST的入门题,代码是 ...

  4. MarkDown不支持图片放缩。。

    ![](http://images2015.cnblogs.com/blog/573995/201604/573995-20160430162211050-1357272526.jpg =100x20 ...

  5. 错误名称:Uncaught SyntaxError: Unexpected identifier

    控制台输出: 1.谷歌:Uncaught SyntaxError: Unexpected identifier 2.火狐:SyntaxError: missing ] after element li ...

  6. bzoj 2160: 拉拉队排练 回文自动机

    题目: Description 艾利斯顿商学院篮球队要参加一年一度的市篮球比赛了.拉拉队是篮球比赛的一个看点,好的拉拉队往往能帮助球队增加士气,赢得最终的比赛.所以作为拉拉队队长的楚雨荨同学知道,帮助 ...

  7. bzoj 2553: [BeiJing2011]禁忌 AC自动机+矩阵乘法

    题目大意: http://www.lydsy.com/JudgeOnline/problem.php?id=2553 题解: 利用AC自动机的dp求出所有的转移 然后将所有的转移储存到矩阵中,进行矩阵 ...

  8. 汇编题目:在屏幕中间显示a-z的所有字母,按ESC键改变字符颜色

    在屏幕中显示a-z字母,按ESC键改变字符颜色. ;程序功能:在屏幕中间同一点显示a-z的所有字符 ; 1.使用cpu循环空运行实现延迟 ; 2.按ESC键改变正在循环显示的字符的颜色 ; 3.程序完 ...

  9. 麻省理工《C内存管理和C++面向对象编程》笔记---第一讲:认识C和内存管理

    最近一年都在用.net和Java,现在需要用C了.昨天看到博客园首页的麻省理工开放课程,就找来看看,正好复习一下.这门<C内存管理和C++面向对象编程>不是那种上来就变量,循环的千篇一律的 ...

  10. Parallel Programming-Task Base

    Parallel.For/ForEach是数据层面的并行,本文所讲的Task是将不同的操作并行执行,本文主要内容: Task的工作模型 初始化Task 完成Task 取消Task 一.Task工作模型 ...