luogu P4168 [Violet]蒲公英
分块经典题竟然是一道黑题……
分块求区间众数的大体思想是对于询问区间[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]蒲公英的更多相关文章
- Luogu P4168 [Violet]蒲公英 分块
这道题算是好好写了.写了三种方法. 有一个好像是$qwq$$N\sqrt(N)$的方法,,但是恳请大佬们帮我看看为什么这么慢$qwq$(后面的第三种) 注:$pos[i]$表示$i$属于第$pos[i ...
- 洛谷 P4168 [Violet]蒲公英 解题报告
P4168 [Violet]蒲公英 题目背景 亲爱的哥哥: 你在那个城市里面过得好吗? 我在家里面最近很开心呢.昨天晚上奶奶给我讲了那个叫「绝望」的大坏蛋的故事的说!它把人们的房子和田地搞坏,还有好多 ...
- P4168 [Violet]蒲公英 区间众数
$ \color{#0066ff}{ 题目描述 }$ 在乡下的小路旁种着许多蒲公英,而我们的问题正是与这些蒲公英有关. 为了简化起见,我们把所有的蒲公英看成一个长度为n的序列 \((a_1,a_2.. ...
- 洛谷 P4168 [Violet] 蒲公英
历尽千辛万苦终于AC了这道题目... 我们考虑1个区间\([l,r]\), 被其完整包含的块的区间为\([L,R]\) 那么众数的来源? 1.\([l,L)\)或\((R,r]\)中出现的数字 2.\ ...
- P4168 [Violet]蒲公英
神仙分块题?其实还是很简单的,res[i][j]表示第i块到第j块的众数,然后再用sum[i][j]表示前i块中j这个种类出现的次数,然后分块瞎搞就行了,感觉我写的十分简洁,好评( //author ...
- p4168 [Violet]蒲公英(分块)
区间众数的重题 和数列分块入门9双倍经验还是挺好的 然后开O2水过 好像有不带log的写法啊 之后在补就是咕咕咕 // luogu-judger-enable-o2 #include <cstd ...
- [洛谷P4168][Violet]蒲公英
题目大意:有$n(n\leqslant4\times10^4)$个数,$m(m\leqslant5\times10^4)$个询问,每次问区间$[l,r]$内的众数,若相同输出最小的,强制在线. 题解: ...
- Luogu P1445[Violet]樱花/P4167 [Violet]樱花
Luogu P1445[Violet]樱花/P4167 [Violet]樱花 真·双倍经验 化简原式: $$\frac{1}{x}+\frac{1}{y}=\frac{1}{n!}$$ $$\frac ...
- luogu P4168 蒲公英+ 分块学习笔记
传送门 题目描述 在乡下的小路旁种着许多蒲公英,而我们的问题正是与这些蒲公英有关. 为了简化起见,我们把所有的蒲公英看成一个长度为n的序列\((a_1,a_2..a_n)\),其中 \(a_i\)为一 ...
随机推荐
- (转)python strip()函数 去空格\n\r\t函数的用法
原文:http://www.cnblogs.com/zdz8207/p/python_learn_note_20.html python3.4学习笔记(二十) python strip()函数 去空格 ...
- ionic resources
下面是我在使用ionic,cordova,angularjs的时候经常使用的资源. ionic css components cordova documentation ionic icons ngC ...
- Android中改变Activity的不同icon:activity-alias
Android设置title中的Icon有几种方法,介绍如下: 一种是直接在AndroidManifest.xml文件中设置android:icon属性,这种方法简单有效,应该算是我们最常用的设置Ic ...
- xlua的自定义加载
具体可以先看xlua的自定义加载的demo,那个用lamda表达式做的 我这个更好理解 主要是ReadFile2的结构问题,必须的写成这样
- 转:JAVA线程池ThreadPoolExecutor与阻塞队列BlockingQueue
从Java5开始,Java提供了自己的线程池.每次只执行指定数量的线程,java.util.concurrent.ThreadPoolExecutor 就是这样的线程池.以下是我的学习过程. 首先是构 ...
- React.js 小书 Lesson18 - 挂载阶段的组件生命周期(一)
作者:胡子大哈 原文链接:http://huziketang.com/books/react/lesson18 转载请注明出处,保留原文链接和作者信息. 我们在讲解 JSX 的章节中提到,下面的代码: ...
- 使用setInterval函数改变网页背景的颜色
var icolor=0; var iNum=256; var iID=setInterval(setbgColor, 500); function setbgColor() { body.backg ...
- [转]解读ASP.NET 5 & MVC6系列(8):Session与Caching
本文转自:http://www.cnblogs.com/TomXu/p/4496445.html 在之前的版本中,Session存在于System.Web中,新版ASP.NET 5中由于不在依赖于Sy ...
- tomcat一个IP绑定多个域名,不同域名访问不同的应用
修改conf文件夹下面的server.xml的Engine里面的内容即可原始内容如下: …… <Engine name="Catalina" defaultHost=&quo ...
- 2017 年 9 月 27 日 js(1.两个select 内容互换 2.单选按钮 同意可点击下一步 3. 全选框)
1.两个select 内容互换 <!DOCTYPE html><html> <head> <meta charset="UTF- ...