[洛谷P5048][Ynoi2019模拟赛]Yuno loves sqrt technology III
题目大意:有$n(n\leqslant5\times10^5)$个数,$m(m\leqslant5\times10^5)$个询问,每个询问问区间$[l,r]$中众数的出现次数
题解:分块,设块大小为$S$,先可以预处理出两两块之间的众数出现次数,复杂度$O(\Big(\dfrac n S\Big)n)$。询问时先把答案设成整块内的答案,然后对两边剩下的最多$2S$个元素进行讨论。
难点在如何快速求出一个元素在区间内出现次数,先想到的是主席树,但是多了一个$\log_2$,并过不去。可以把每种数出现的位置用$vector$存下来,并且对每个数存一个它在$vector$中的位置,第$i$个数的位置是$ret_i$,假设现在的答案为$ans$,正在处理左边的多余元素,处理到第$i$个,可以看这个数值的$vector$中,第$ret_i+ans$位是否小于$r$,若小于,则这个数至少出现了$ans+1$次,更新答案。右边也是类似的。
发现$ans$最多自增$2S$次,所以一次查询的复杂度是$O(2S)$的,总复杂度为$O(2Sm+\Big(\dfrac n S\Big)n)$,当$S$略小于$\sqrt n$时最优(其实是我不怎么算)
卡点:$Ynoi$当然卡常啦
C++ Code:
#include <algorithm>
#include <cstdio>
#include <cctype>
#include <vector> namespace std {
struct istream {
#define M (1 << 24 | 3)
char buf[M], *ch = buf - 1;
inline istream() {
#ifndef ONLINE_JUDGE
freopen("input.txt", "r", stdin);
#endif
fread(buf, 1, M, stdin);
}
inline istream& operator >> (int &x) {
while (isspace(*++ch));
for (x = *ch & 15; isdigit(*++ch); ) x = x * 10 + (*ch & 15);
return *this;
}
#undef M
} cin;
struct ostream {
#define M (1 << 24 | 3)
char buf[M], *ch = buf - 1;
int w;
inline ostream& operator << (int x) {
if (!x) {
*++ch = '0';
return *this;
}
for (w = 1; w <= x; w *= 10);
for (w /= 10; w; w /= 10) *++ch = (x / w) ^ 48, x %= w;
return *this;
}
inline ostream& operator << (const char x) {*++ch = x; return *this;}
inline ostream& operator << (const char *x) {
while (*x) *this << *x++;
return *this;
}
inline ~ostream() {
#ifndef ONLINE_JUDGE
freopen("output.txt", "w", stdout);
#endif
fwrite(buf, 1, ch - buf + 1, stdout);
}
#undef M
} cout;
} #define maxn 500010
const int BSZ = 610, BNUM = maxn / BSZ + 10; int cnt[maxn];
int MAX[BNUM][BNUM];
int L[maxn], R[maxn], bel[maxn]; int n, m, Bnum;
int w[maxn], v[maxn]; std::vector<int> list[maxn];
int ret[maxn];
int main() {
std::cin >> n >> m;
for (int i = 1; i <= n; i++) {
std::cin >> w[i];
v[i] = w[i];
bel[i] = (i - 1) / BSZ + 1;
} const int tot = (std::sort(v + 1, v + n + 1), std::unique(v + 1, v + n + 1) - v - 1);
for (int i = 1; i <= n; i++) {
w[i] = std::lower_bound(v + 1, v + tot + 1, w[i]) - v;
ret[i] = list[w[i]].size();
list[w[i]].push_back(i);
} Bnum = bel[n];
for (int i = 1; i <= Bnum; i++) {
L[i] = (i - 1) * BSZ, R[i] = L[i] + BSZ - 1;
}
L[1] = 1, R[Bnum] = n;
for (int i = 1; i <= Bnum; i++) {
__builtin_memset(cnt, 0, sizeof cnt);
int Max = 0, now = i;
for (int j = L[i]; j <= n; j++) {
cnt[w[j]]++;
Max = std::max(Max, cnt[w[j]]);
if (j == R[now]) {
MAX[i][now] = Max;
now++;
}
}
} int ans = 0;
while (m --> 0) {
int l, r;
std::cin >> l >> r;
l ^= ans, r ^= ans;
const int lb = bel[l], rb = bel[r];
ans = 0;
if (lb == rb) {
for (int i = l; i <= r; i++) {
const int W = w[i], sz = list[W].size(), pos = ret[i];
while (pos + ans < sz && list[W][pos + ans] <= r) ans++;
}
} else {
if (lb + 1 < rb) ans = MAX[lb + 1][rb - 1];
for (int i = l; i <= R[lb]; i++) {
const int W = w[i], sz = list[W].size(), pos = ret[i];
while (pos + ans < sz && list[W][pos + ans] <= r) ans++;
}
for (int i = L[rb]; i <= r; i++) {
const int W = w[i], pos = ret[i];
while (pos >= ans && list[W][pos - ans] >= l) ans++;
}
}
std::cout << ans << '\n';
}
return 0;
}
[洛谷P5048][Ynoi2019模拟赛]Yuno loves sqrt technology III的更多相关文章
- 洛谷P5048 [Ynoi2019模拟赛]Yuno loves sqrt technology III(分块)
传送门 众所周知lxl是个毒瘤,Ynoi道道都是神仙题 用蒲公英那个分块的方法做结果两天没卡过去→_→ 首先我们分块,预处理块与块之间的答案,然后每次询问的时候拆成整块和两边剩下的元素 整块的答案很简 ...
- 洛谷 P5048 - [Ynoi2019 模拟赛] Yuno loves sqrt technology III(分块)
题面传送门 qwq 感觉跟很多年前做过的一道题思路差不多罢,结果我竟然没想起那道题?!!所以说我 wtcl/wq 首先将 \(a_i\) 离散化. 如果允许离线那显然一遍莫队就能解决,复杂度 \(n\ ...
- 洛谷 P5046 [Ynoi2019 模拟赛] Yuno loves sqrt technology I(分块+卡常)
洛谷题面传送门 zszz,lxl 出的 DS 都是卡常题( 首先由于此题强制在线,因此考虑分块,我们那么待查询区间 \([l,r]\) 可以很自然地被分为三个部分: 左散块 中间的整块 右散块 那么这 ...
- Luogu P5048 [Ynoi2019模拟赛]Yuno loves sqrt technology III 分块
这才是真正的$N\sqrt{N}$吧$qwq$ 记录每个数$vl$出现的位置$s[vl]$,和每个数$a[i]=vl$是第几个$vl$,记为$P[i]$,然后预处理出块$[i,j]$区间的答案$f[i ...
- P5048 [[Ynoi2019模拟赛]Yuno loves sqrt technology III]
为什么我感觉这题难度虚高啊-- 区间众数的出现次数- 计算器算一下 \(\sqrt 500000 = 708\) 然后我们发现这题的突破口? 考虑分块出来[L,R]块的众数出现个数 用 \(\text ...
- [luogu5048] [Ynoi2019模拟赛] Yuno loves sqrt technology III
题目链接 洛谷. Solution 思路同[BZOJ2724] [Violet 6]蒲公英,只不过由于lxl过于毒瘤,我们有一些更巧妙的操作. 首先还是预处理\(f[l][r]\)表示\(l\sim ...
- [Ynoi2019模拟赛]Yuno loves sqrt technology III
题目大意: 给你一个长为n的序列a,m次询问,每次查询一个区间的众数的出现次数,强制在线. 解题思路: 出题人题解 众所周知lxl是个毒瘤,Ynoi道道都是神仙题 首先得离散化. 分块后,预处理Fi, ...
- [Luogu5048] [Ynoi2019模拟赛]Yuno loves sqrt technology III[分块]
题意 长为 \(n\) 的序列,询问区间众数,强制在线. \(n\leq 5\times 10^5\). 分析 考虑分块,暴力统计出整块到整块之间的众数次数. 然后答案还可能出现在两边的两个独立的块中 ...
- [Ynoi2019模拟赛]Yuno loves sqrt technology I
题目描述 给你一个长为n的排列,m次询问,每次查询一个区间的逆序对数,强制在线. 题解 MD不卡了..TMD一点都卡不动. 强制在线的话也没啥好一点的方法,只能分块预处理了. 对于每个块,我们设lef ...
随机推荐
- MySQL高级-showProfile
一.Show Profile是什么? 是MySql提供可以用来分析当前会话中语句执行的资源消耗情况,可以用于SQL的调优的测量. 默认情况下,参数处于关闭状态,并保存最近15次的运行结果. 二.分析步 ...
- excell 导入 导出
1.jar包 2.POIUtils工具类 package com.esstglobal.service.utils; import java.io.BufferedInputStream; impor ...
- leetcode-岛屿的个数
岛屿的个数 给定一个由 '1'(陆地)和 '0'(水)组成的的二维网格,计算岛屿的数量.一个岛被水包围,并且它是通过水平方向或垂直方向上相邻的陆地连接而成的.你可以假设网格的四个边均被水包围. 示例 ...
- Java学习 · 初识 多线程
多线程 1. 基础概念 a) 程序 Program i. 静态代码,指令集,应用程序执行的蓝本 b) 进程 Process i. 动态概念,正在运 ...
- 谜题 (Puzzle,ACM/ICPC World Finals 1993,UVa227)
题目描述:算法竞赛入门经典习题3-5 题目思路:模拟题 #include <stdio.h> #include <string.h> #define maxn 55 char ...
- Android开发-API指南-<receiver>
<receiver> 英文原文:http://developer.android.com/guide/topics/manifest/receiver-element.html 采集(更新 ...
- poj 3468 (区间修改 区间查询)
A Simple Problem with Integers Time Limit: 5000MS Memory Limit: 131072K Total Submissions:147133 ...
- 机器学习之支持向量机(Support Vector Machine)
转载请注明出处:http://www.cnblogs.com/Peyton-Li/ 支持向量机 支持向量机(support vector machines,SVMs)是一种二类分类模型.它的基本模型是 ...
- Linux下安装paramiko
paramiko是用python语言写的一个模块,遵循SSH2协议,支持以加密和认证的方式,进行远程服务器的连接. 由于使用的是python这样的能够跨平台运行的语言,所以所有python支持的平台, ...
- Python面向对象-访问限制
在Class内部,可以有字段,方法和属性,而外部代码可以通过直接调用实例变量的方法来操作数据, (1)私有普通字段 比如对于下面的Student类,name字段可以在外面通过对象进行直接访问: cla ...