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. 2013面试C++小结

    2013年我在厦门c++求职小结 1.一般公司出的面试题目中的找错误,都是出自平常公司内部使用过程中出现的真实错误. 比如stl 中erase的使用:详细请见 :http://blog.csdn.ne ...

  2. Git_学习_05_ 解决冲突

    二.参考资料 1.使用git pull文件时和本地文件冲突怎么办? 2.git 冲突解决

  3. freeMarker(一)——freeMarker简介

    学习笔记,选自freeMarker中文文档,译自 Email: ddekany at users.sourceforge.net FreeMarker简介: FreeMarker 是一款 模板引擎: ...

  4. Agc012_E Camel and Oases

    传送门 题目大意 坐标轴上有$n$个坐标,第$i$个坐标是$x_i$,初始你有一个容量$V$,当两个给定的坐标距离不超过$V$时,你可以从一个坐标到达另一个坐标,同时你还可以令$V=\lfloor \ ...

  5. 1038 Recover the Smallest Number (30)(30 分)

    Given a collection of number segments, you are supposed to recover the smallest number from them. Fo ...

  6. 【JVM】java棧

    java棧和函数调用的关系图 [名词解释]--->java棧是一块线程的私有空间--->java的棧是先进后出的数据结构.函数返回,则该函数的棧帧被弹出.--->一个函数对应一个棧帧 ...

  7. ACM学习历程—广东工业大学2016校赛决赛-网络赛E 积木积水(最值问题 || 动态规划)

    题目链接:http://gdutcode.sinaapp.com/problem.php?cid=1031&pid=4 这个题目自然会考虑到去讨论最长或者最短的板子. 笔上大概模拟一下的话,就 ...

  8. bzoj 4501: 旅行 01分数规划+概率期望dp

    题目大意: http://www.lydsy.com/JudgeOnline/problem.php?id=4501 题解: 首先我们不考虑可以删除边的情况下,如何计算期望边数. 然后我们发现这是个有 ...

  9. C# 中常用LInq操作

    static void Main(string[] args) { , , , , , , }; , , , , , , }; , , , , , , , , , , , }; // 交集 var f ...

  10. RS485总线防雷保护方案

    RS485作为最为最常用的电表通讯方式之一.日常生活中雷电和静电干扰已经成为485通信总线在实际工程经常遇到的问题.故如何对芯片以及总线进行有效的保护,是摆在每一个使用者面前的一个问题.在这里,我们主 ...