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\)为一 ...
随机推荐
- Java 单向链表学习
Java 单向链表学习 链表等同于动态的数组:可以不同设定固定的空间,根据需要的内容动态的改变链表的占用空间和动态的数组同一形式:链表的使用可以更加便于操作. 链表的基本结构包括:链表工具类和节点类, ...
- (转)PowerHA完全手册(一,二,三)
PowerHA完全手册(一) 原文:http://www.talkwithtrend.com/Article/39889-----PowerHA完全手册(一) http://www.talkwitht ...
- (转)Python格式化字符 %s %d %f
Python格式化字符 %s %d %f 原文:http://blog.csdn.net/huangfu77/article/details/54807835 格式 描述%% 百分号标记 #就是输出一 ...
- centos7 中文乱码问题解决方法
1.查看是否安装中文包 可以使用下面的命名查看系统是否安装了中文安装包. locale -a |grep "zh_CN" 没有输出,说明没有安装,输入下面的命令安装: yum gr ...
- Coursera 机器学习 第9章(下) Recommender Systems 学习笔记
9.5 Predicting Movie Ratings9.5.1 Problem Formulation推荐系统.推荐系统的问题表述:电影推荐.根据用户对已看过电影的打分来推测用户对其未打分的电影将 ...
- pat00-自测5. Shuffling Machine (20)
00-自测5. Shuffling Machine (20) 时间限制 400 ms 内存限制 65536 kB 代码长度限制 8000 B 判题程序 Standard 作者 CHEN, Yue Sh ...
- HTML <frameset>不同frame之间传值
布局 左右30%--70%,点击左边的复选框,右边显示相应的反应. 代码 main2.html <html> <frameset cols="30%, 70%"& ...
- nyoj 364——田忌赛马——————【贪心】
田忌赛马 时间限制:3000 ms | 内存限制:65535 KB 难度:3 描述 Here is a famous story in Chinese history. "That ...
- [转]浅谈微信小程序
本文转自:http://www.cnblogs.com/liziyou/p/6340159.html 微信小程序 1.什么是小程序 小程序是指微信公众号平台小程序,小程序可以在微信内被便捷的获取和转播 ...
- 使用vue-router切换页面时,获取上一页url以及当前页面url
今天在实现一个小功能的时候,遇到一个问题,使用vue-router获取上一页面的url信息,我尝试了多种方式,发现使用vue-router的canDeactivate钩子实现这个功能最为方便,现在将我 ...