嘟嘟嘟

分块经典题竟然是一道黑题……

分块求区间众数的大体思想是对于询问区间[L, R],预处理出这中间的整块的众数,然后统计两边零散的数在[L, R]中出现的次数,最后取出现次数最多且最小的数。

因此需要一个sum[i][j]表示前 i 块中数字 j 出现的次数,ans[i][j]表示块 i 到 j 的众数。预处理sum用前缀和的思想,O(n√n)可完成。预处理ans就是枚举左端点是第几个块,然后每一次从这个块的左端点O(n)扫一遍,复杂度也是O(n√n)。

查询的时候,整块的众数即其个数分别是pos = ans[l + 1][r - 1],Max = sum[r - 1][pos] - sum[l][pos]。然后零散的数我们单独开一个数组记录一下,同时记录他在零三部分出现的次数num[i],这样这个数在[L, R]中出现的次数就是sum[r - 1][x] - sum[l][x] + num[x]。最后比较取大。

本题ai较大,所以要离散化,这并不影响众数。

采纳lba大佬的意见,为了避免重复运算从而降低常数,多开了三个数组分别记录每一个数属于哪个块,以及每一个块的左右端点是多少。

 #include<cstdio>
#include<iostream>
#include<cmath>
#include<algorithm>
#include<cstring>
#include<cstdlib>
#include<cctype>
#include<vector>
#include<stack>
#include<queue>
using namespace std;
#define enter puts("")
#define space putchar(' ')
#define Mem(a, x) memset(a, x, sizeof(a))
#define rg register
typedef long long ll;
typedef double db;
const int INF = 0x3f3f3f3f;
const db eps = 1e-;
const int maxn = 4e4 + ;
inline ll read()
{
ll ans = ;
char ch = getchar(), last = ' ';
while(!isdigit(ch)) {last = ch; ch = getchar();}
while(isdigit(ch)) {ans = ans * + ch - ''; ch = getchar();}
if(last == '-') ans = -ans;
return ans;
}
inline void write(ll x)
{
if(x < ) x = -x, putchar('-');
if(x >= ) write(x / );
putchar(x % + '');
} int n, m, a[maxn], t[maxn]; int S, Cnt = , blo[maxn], lb[], rb[];
int sum[][maxn], ans[][], num[maxn];
void init()
{
S = sqrt(n);
Cnt = (n % S) ? n / S : n / S + ;
for(int i = ; i <= Cnt; ++i) lb[i] = (i - ) * S, rb[i] = i * S - ;
rb[Cnt] = n; //一定要有,否则会gg
for(int i = , j = ; i <= n; ++i) blo[i] = j, j += (i == rb[j]);
for(int i = ; i <= Cnt; ++i)
{
for(int j = ; j <= n; ++j) sum[i][j] += sum[i - ][j];
for(int j = lb[i]; j <= rb[i]; ++j) sum[i][a[j]]++;
}
for(int i = ; i <= Cnt; ++i)
{
Mem(num, ); int Max = -, pos;
for(int j = lb[i], k = i; j <= n; ++j)
{
if(++num[a[j]] > Max) Max = num[a[j]], pos = a[j];
if(num[a[j]] == Max && a[j] < pos) pos = a[j];
if(j == rb[k]) ans[i][k] = pos, k++;
}
}
}
int temp[], cp = ;
int query(int L, int R)
{
Mem(num, ); cp = ;
int l = blo[L], r = blo[R];
int Max = -, pos;
if(l == r)
{
for(int i = L; i <= R; ++i)
{
if(++num[a[i]] > Max) Max = num[a[i]], pos = a[i];
if(num[a[i]] == Max && a[i] < pos) pos = a[i];
}
return pos;
}
pos = ans[l + ][r - ]; Max = sum[r - ][pos] - sum[l][pos];
for(int i = L; i <= rb[l]; ++i)
{
if(!num[a[i]]) temp[++cp] = a[i];
num[a[i]]++;
}
for(int i = lb[r]; i <= R; ++i)
{
if(!num[a[i]]) temp[++cp] = a[i];
num[a[i]]++;
}
for(int i = ; i <= cp; ++i)
{
int tp = sum[r - ][temp[i]] - sum[l][temp[i]] + num[temp[i]];
if(tp > Max) Max = tp, pos = temp[i];
if(tp == Max && temp[i] < pos) pos = temp[i];
}
return pos;
} int Ans = ; int main()
{
n = read(); m = read();
for(int i = ; i <= n; ++i) t[i] = a[i] = read();
sort(t + , t + n + );
int _n = unique(t + , t + n + ) - t - ;
for(int i = ; i <= n; ++i)
a[i] = lower_bound(t + , t + _n + , a[i]) - t;
init();
for(int i = ; i <= m; ++i)
{
int L = read(), R = read();
L = (L + Ans - ) % n + ; R = (R + Ans - ) % n + ;
if(L > R) swap(L, R);
Ans = t[query(L, R)]; //别忘了输出原数
write(Ans), enter;
}
return ;
}

luogu P4168 [Violet]蒲公英的更多相关文章

  1. Luogu P4168 [Violet]蒲公英 分块

    这道题算是好好写了.写了三种方法. 有一个好像是$qwq$$N\sqrt(N)$的方法,,但是恳请大佬们帮我看看为什么这么慢$qwq$(后面的第三种) 注:$pos[i]$表示$i$属于第$pos[i ...

  2. 洛谷 P4168 [Violet]蒲公英 解题报告

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

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

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

  4. 洛谷 P4168 [Violet] 蒲公英

    历尽千辛万苦终于AC了这道题目... 我们考虑1个区间\([l,r]\), 被其完整包含的块的区间为\([L,R]\) 那么众数的来源? 1.\([l,L)\)或\((R,r]\)中出现的数字 2.\ ...

  5. P4168 [Violet]蒲公英

    神仙分块题?其实还是很简单的,res[i][j]表示第i块到第j块的众数,然后再用sum[i][j]表示前i块中j这个种类出现的次数,然后分块瞎搞就行了,感觉我写的十分简洁,好评( //author ...

  6. p4168 [Violet]蒲公英(分块)

    区间众数的重题 和数列分块入门9双倍经验还是挺好的 然后开O2水过 好像有不带log的写法啊 之后在补就是咕咕咕 // luogu-judger-enable-o2 #include <cstd ...

  7. [洛谷P4168][Violet]蒲公英

    题目大意:有$n(n\leqslant4\times10^4)$个数,$m(m\leqslant5\times10^4)$个询问,每次问区间$[l,r]$内的众数,若相同输出最小的,强制在线. 题解: ...

  8. Luogu P1445[Violet]樱花/P4167 [Violet]樱花

    Luogu P1445[Violet]樱花/P4167 [Violet]樱花 真·双倍经验 化简原式: $$\frac{1}{x}+\frac{1}{y}=\frac{1}{n!}$$ $$\frac ...

  9. luogu P4168 蒲公英+ 分块学习笔记

    传送门 题目描述 在乡下的小路旁种着许多蒲公英,而我们的问题正是与这些蒲公英有关. 为了简化起见,我们把所有的蒲公英看成一个长度为n的序列\((a_1,a_2..a_n)\),其中 \(a_i\)为一 ...

随机推荐

  1. Lakeshore

    用来做 html5 特效,Egret游戏引擎 为什么用Egret开发的游戏在某些Android设备上特别卡? { 在 Android 早期版本( 4.4 之前) ,Android WebView 并不 ...

  2. UnityError The same field name is serialized multiple times in the class or its parent class. This is not supported: Base(MonoBehaviour) i

    相同的字段名在类或其父类中被多次序列化.这是不支持的, 这里指的是 变量i . 写如下两个脚本挂到新项目的相机上运行就会出现这个问题: public class Father : MonoBehavi ...

  3. Java基础17-成员变量、return关键字和多参方法

    1.成员变量 在类中声明的变量为成员变量 //Dog类 class Dog{ String name;//成员变量 } public class Test1{ public static void m ...

  4. jquery通过submit()和serialize()提交表单

    <script type="text/javascript"> $(function() { $('#form1').submit(function() { //当提交 ...

  5. flask表单flask-wtf

    一.安装pip install flask-wtf 二.创建一个flask的项目引入相对应的包 from flask import Flask,render_template import flask ...

  6. 自己实现C++的string类

    使用C++的朋友对string类都不会陌生,string类使用起来很是方便,比C的字符数组好用多了,但是我们能不能自己实现一个属于自己的string类呢? 实现一个具有基本功能的string类并不难, ...

  7. jQuery小测验

    1.在div元素中,包含了一个<span>元素,通过has选择器获取<div>元素中的<span>元素的语法是? 提示使用has() $(div:has(span) ...

  8. c语言进制转化

    #include <stdio.h> // 进制转化 int main(void) { ; ; int i3 = 0x32C; printf( printf( printf("十 ...

  9. Tesorflow源代码安装方式以及错误的解决方法

    作者 修雨轩陈@cnblog 目录 Configure the installation. (安装配置) Create the pip package and install (创建pip安装包并且安 ...

  10. Spring MVC开发初体验

    1.目标实现Spring MVC : Hello World! 2.工程创建步骤 new : Dynamic Web Project lib引入Spring框架libs/*.jar touch web ...