嘟嘟嘟

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

分块求区间众数的大体思想是对于询问区间[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. scala 列表的子集判断

    val list1=List.range(0,5) val list2=List.range(0,2) val list3=List(0,6) list1.contains(2) list1.cont ...

  2. 小程序 开发阶段请求网络报 不在以下 request 合法域名列表中

    1.在工具栏右边,点开详情, 把图片最后一项选上,再重新编译一下项目就可以了. 2.管理员将需要使用的域名添加到小程序后台 1. 地址:http://mp.weixin.qq.com (需要请求的域名 ...

  3. [转]NetCat简介

    NetCat是一个非常简单的Unix工具,可以读.写TCP或UDP网络连接(network connection).它被设计成一个可靠的后端(back-end) 工具,能被其它的程序或脚本直接地或容易 ...

  4. css使用text-align: justify不能实现两段对其的问题解决方式

    一行文本不进行处理.还有就是强制换行的也不处理.所以你强制占满(在后面加个span)了一行他才处理 <p class="home">test test test < ...

  5. [转]实例化SqlParameter时,如果是字符型,一定要指定size属性

    转自:http://bbs.csdn.net/topics/380155255 以前在实例化SqlParameter时,通常都是用下面的语句,没有设置size属性: new SqlParameter( ...

  6. 线程同步(windows平台):事件

    一:介绍 事件Event实际上是个内核对象,事件分两种状态:激发状态和未激发状态.分两种类型:手动处置事件和自动处置事件.手动处置事件被设置为激发状态后,会唤醒所有等待的线程,一直保持为激发状态,直到 ...

  7. UI特效资料-----ShaderWeaver

    主页:www.shaderweaver.com教程:www.shaderweaver.com/tutorials.html 1.一款插件,挺强大的 ShaderWeaver使用教程-基本操作介绍 ht ...

  8. unity向量-数学-三角函数

    1.如何在unity写cos60 Mathf.Cos(Mathf.Deg2Rad * ) Deg2Rad将 60 角度转换为弧度,因为里面参数只能填弧度数 2.计算一个Vector3绕旋转中心旋转指定 ...

  9. Android触摸事件传递机制

    简单梳理一下Android触摸事件传递机制的知识点. 一.View与ViewGroup的关系 View和ViewGroup二者的继承关系如下图所示: View是Android中最基本的一种UI组件,它 ...

  10. mysql的引擎和锁