loj 数列分块入门 6 9(区间众数)
6
题意
给出一个长为\(n\)的数列,以及\(n\)个操作,操作涉及单点插入,单点询问,数据随机生成。
题解
每个块内用一个\(vector\)维护,每次插入时先找到位置所在的块,再暴力插入。
如果数据不随机,即如果先在一个块有大量单点插入,这个块的大小会大大超过\(\sqrt n\),那块内的暴力就没有复杂度保证了。
为此引入一个操作:重新分块(重构)
每\(\sqrt n\)次插入后,重新把数列平均分一下块,重构需要的复杂度为\(O(n)\),重构的次数为\(\sqrt n\),所以重构的复杂度没有问题,而且保证了每个块的大小相对均衡。
当然,也可以当某个块过大时重构,或者只把这个块分成两半。
// 代码中采取的是当块过大时进行重构。
Code
#include <bits/stdc++.h>
#define maxn 200010
#define C 20
#define F(i, a, b) for (int i = (a); i < (b); ++i)
#define F2(i, a, b) for (int i = (a); i <= (b); ++i)
#define dF(i, a, b) for (int i = (a); i > (b); --i)
#define dF2(i, a, b) for (int i = (a); i >= (b); --i)
using namespace std;
typedef long long LL;
int n, blo, a[maxn], num;
vector<int> v[510];
struct node { int bl, p; };
node query(int p) {
int i=0;
while (p>v[i].size()) p -= v[i++].size();
return {i, p-1};
}
void rebuild() {
int cnt=0;
F(i, 0, num) {
for (auto x : v[i]) a[cnt++] = x;
v[i].clear();
}
blo = sqrt(cnt); num = (cnt+blo-1)/blo;
F(i, 0, cnt) v[i/blo].push_back(a[i]);
}
void insert(int p, int x) {
node nd = query(p);
v[nd.bl].insert(v[nd.bl].begin()+nd.p, x);
if (v[nd.bl].size()>C*blo) rebuild();
}
int main() {
scanf("%d", &n); blo = sqrt(n);
F(i, 0, n) {
scanf("%d", &a[i]);
v[i/blo].push_back(a[i]);
}
num = (n+blo-1)/blo;
F(i, 0, n) {
int op, l, r, c;
scanf("%d%d%d%d", &op, &l, &r, &c);
if (op) {
node nd = query(r);
printf("%d\n", v[nd.bl][nd.p]);
}
else insert(l, r);
}
return 0;
}
9
题意
给出一个长为\(n\)的数列,以及\(n\)个操作,操作涉及询问区间的最小众数。
题解
离散化。
对每一个数开一个桶,即对每个数用一个\(vector\)按序记录它所有的出现位置。
预处理出\(f[s][t]\)表示第\(s\)块到第\(t\)块的最小众数:
方法是:枚举\(s\),向右扫,每扫一个块得到一个值。
复杂度:\(\sqrt n*\sqrt n+(\sqrt n-1)*\sqrt n+\cdots+2*\sqrt n+\sqrt n=\sqrt n*(1+2+\cdots+\sqrt n)=O(n\sqrt n)\)对于一个询问\([l,r]\):
不完整的块中共有\(2\sqrt n\)个数,完整的块根据3. 中的预处理得到一个数。
暴力比较这\(2\sqrt n+1\)个数的出现次数,
方法是:要知道\(x\)在\([l,r]\)中的出现次数,只需在\(vector[x]\)中进行二分查找。
复杂度:\(O(\sqrt n*logn)\)
Code
#include <bits/stdc++.h>
#define F(i, a, b) for (int i = (a); i < (b); ++i)
#define F2(i, a, b) for (int i = (a); i <= (b); ++i)
#define dF(i, a, b) for (int i = (a); i > (b); --i)
#define dF2(i, a, b) for (int i = (a); i >= (b); --i)
#define maxn 100010
#define inf 0x3f3f3f3f
using namespace std;
int cnt[maxn], a[maxn], n, num, blo, f[1010][1010], bl[maxn], mp2[maxn];
map<int, int> mp;
vector<int> v[maxn];
typedef long long LL;
inline void update(int temp, int& maxx, int x, int& ans) {
if (temp>maxx || (temp==maxx&&mp2[x]<mp2[ans])) {
maxx = temp, ans = x;
}
}
void pre(int s) {
memset(cnt, 0, sizeof cnt);
int ans = -inf, maxx = 0;
F(i, s, num) {
F(j, i*blo, min((i+1)*blo, n)) {
++cnt[a[j]];
update(cnt[a[j]], maxx, a[j], ans);
}
f[s][i] = ans;
}
}
inline int count(int l, int r, int x) {
return upper_bound(v[x].begin(), v[x].end(), r)-upper_bound(v[x].begin(), v[x].end(), l-1);
}
int query(int l, int r) {
int ans = -inf, maxx = 0;
F(i, l, min(r+1, (bl[l]+1)*blo)) {
int temp = count(l, r, a[i]);
update(temp, maxx, a[i], ans);
}
if (bl[l]!=bl[r]) {
F2(i, bl[r]*blo, r) {
int temp = count(l, r, a[i]);
update(temp, maxx, a[i], ans);
}
}
if (bl[l]+1<=bl[r]-1) {
int x = f[bl[l]+1][bl[r]-1];
int temp = count(l, r, x);
update(temp, maxx, x, ans);
}
return ans;
}
int main() {
scanf("%d", &n); blo = sqrt(n);
int tot=0;
F(i, 0, n) {
scanf("%d", &a[i]);
if (!mp[a[i]]) {
mp[a[i]] = ++tot;
mp2[tot] = a[i];
}
bl[i] = i/blo;
v[a[i]=mp[a[i]]].push_back(i);
}
num = bl[n-1]+1;
F(i, 0, num) pre(i);
F(i, 0, n) {
int l, r;
scanf("%d%d", &l, &r); --l, --r;
printf("%d\n", mp2[query(l, r)]);
}
return 0;
}
loj 数列分块入门 6 9(区间众数)的更多相关文章
- LOJ #6283. 数列分块入门 7-分块(区间乘法、区间加法、单点查询)
#6283. 数列分块入门 7 内存限制:256 MiB时间限制:500 ms标准输入输出 题目类型:传统评测方式:文本比较 上传者: hzwer 提交提交记录统计测试数据讨论 2 题目描述 给出 ...
- LOJ #6281. 数列分块入门 5-分块(区间开方、区间求和)
#6281. 数列分块入门 5 内存限制:256 MiB时间限制:500 ms标准输入输出 题目类型:传统评测方式:文本比较 上传者: hzwer 提交提交记录统计测试数据讨论 5 题目描述 给出 ...
- LOJ #6280. 数列分块入门 4-分块(区间加法、区间求和)
#6280. 数列分块入门 4 内存限制:256 MiB时间限制:500 ms标准输入输出 题目类型:传统评测方式:文本比较 上传者: hzwer 提交提交记录统计测试数据讨论 题目描述 给出一个 ...
- LOJ #6279. 数列分块入门 3-分块(区间加法、查询区间内小于某个值x的前驱(比其小的最大元素))
#6279. 数列分块入门 3 内存限制:256 MiB时间限制:1500 ms标准输入输出 题目类型:传统评测方式:文本比较 上传者: hzwer 提交提交记录统计测试数据讨论 3 题目描述 给 ...
- LOJ #6278. 数列分块入门 2-分块(区间加法、查询区间内小于某个值x的元素个数)
#6278. 数列分块入门 2 内存限制:256 MiB时间限制:500 ms标准输入输出 题目类型:传统评测方式:文本比较 上传者: hzwer 提交提交记录统计测试数据讨论 6 题目描述 给出 ...
- LOJ #6277. 数列分块入门 1-分块(区间加法、单点查询)
#6277. 数列分块入门 1 内存限制:256 MiB时间限制:100 ms标准输入输出 题目类型:传统评测方式:文本比较 上传者: hzwer 提交提交记录统计测试数据讨论 2 题目描述 给出 ...
- [Loj] 数列分块入门 1 - 9
数列分块入门 1 https://loj.ac/problem/6277 区间加 + 单点查询 #include <iostream> #include <cstdio> #i ...
- loj 数列分块入门 5 7 8
5 题意 给出一个长为\(n\)的数列,以及\(n\)个操作,操作涉及区间开方,区间求和. 思路 用\(tag\)记录这一块是否已全为\(1\). 除分块外,还可用 树状数组+并查集(链表) 或者 线 ...
- LOJ 数列分块入门系列
目录 1.区间加+单点查 每个块维护tag,散的暴力改. code: #include<bits/stdc++.h> using namespace std; const int maxn ...
随机推荐
- 如何在创建hive表格的python代码中导入外部文件
业务场景大概是这样的,我要对用户博文进行分词(这个步骤可以看这篇文章如何在hive调用python的时候使用第三方不存在的库-how to use external python library in ...
- python爬虫:利用BeautifulSoup爬取链家深圳二手房首页的详细信息
1.问题描述: 爬取链家深圳二手房的详细信息,并将爬取的数据存储到Excel表 2.思路分析: 发送请求--获取数据--解析数据--存储数据 1.目标网址:https://sz.lianjia.com ...
- C语言进阶——有符号与无符号02
在计算机的内部,我们所有的信息都是由二进制数字组成的 有符号数的表实法: 在计算机内部用补码的方式表实有符号数 正数的补码位正数的本身 负数的补码为其绝对值取反然后加一得到 例如-7 他在计算机内部的 ...
- 通过集群的方式解决基于MQTT协议的RabbitMQ消息收发
在完成了基于AMQP协议的RabbitMQ消息收发后,我们要继续实现基于MQTT协议的RabbitMQ消息收发. 由于C#的RabbitMQ.Client包中只实现了基于AMQP协议的消息收发功能的封 ...
- poj 3087 直接模拟
题意:意思就是,s1,和s2两堆牌,然后先s2一张再s1,最后会出现一个s12序列,例如s1 AHAH S2 HAHA 然后s12为HAAHHAAH,然后前面一部分给s1,后面一部分给s2,然后再重复 ...
- android gradle 给所有的buildFlavor 的versionName 增加一个后缀
build里面有很多的productFlavors,我想要给所有的productFlavors 的versionName增加一个后缀比如:_20180323 怎么做?注意是所有的productFlav ...
- Eclipse 创建 Java 接口---Eclipse教程第11课
打开新建 Java 接口向导 新建 Java 接口向导可以创建新的 Java 接口.打开向导的方式有: 点击 File 菜单并选择 New > Interface 在 Package Explo ...
- 《数据结构与算法分析:C语言描述》复习——第八章“并查集”——并查集
2014.06.18 14:16 简介: “并查集”,英文名为“union-find set”,从名字就能看出来它支持合并与查找功能.另外还有一个名字叫“disjoint set”,中文名叫不相交集合 ...
- 易语言.开源(vip视频播放器源码)
下载链接:https://pan.baidu.com/s/1ta1Ig3LOiOka-kr5xB18kw
- 3D U-Net卷积神经网络
3D U-Net这篇论文的诞生主要是为了处理一些块状图(volumetric images),基本的原理跟U-Net其实并无大差,因为3D U-Net就是用3D卷积操作替换了2D的,不过在这篇博文中我 ...