• 博客园logo
  • 会员
  • 众包
  • 新闻
  • 博问
  • 闪存
  • 赞助商
  • HarmonyOS
  • Chat2DB
    • 搜索
      所有博客
    • 搜索
      当前博客
  • 写随笔 我的博客 短消息 简洁模式
    用户头像
    我的博客 我的园子 账号设置 会员中心 简洁模式 ... 退出登录
    注册 登录

RomanLin

  • 博客园
  • 联系
  • 订阅
  • 管理

公告

View Post

【分块】LibreOJ 6282 数列分块入门6

题目

https://loj.ac/p/6282

题解

数据范围 \(1 \leq n \leq 10^5\),因此进行分块最多分 \(\sqrt{10^5} ≈ 318\) 块。且数据是随机生成的,因此插入数据后,每个块的长度期望值为 \(\frac{318+(318 + 100000/318)}{2} ≈ 475\)。因此,可以使用分块思想解决该问题。

对于每个块,都用一个数组维护,并且维护每个块的元素个数。

对于查询操作,从第一块开始累计元素的个数,易知该步骤的时间复杂度为 \(O(\sqrt{n})\)。当找出 \(a_r\) 所在的块的时候,直接取出该元素即可。

对于插入操作,先查询出要插入的元素是需要插入到第几个块,该步操作时间复杂度 \(O(\sqrt{n})\),随后使用插入排序的思想进行插入,由于每个块的块长期望为 \(\sqrt{n}\) 级别,因此该步操作的时间复杂度也是 \(O(\sqrt{n})\)。

参考代码

#include<bits/stdc++.h>
#define IOS ios::sync_with_stdio(false);cin.tie(nullptr);cout.tie(nullptr);
using namespace std;

typedef long long ll;
constexpr int N = 100327;
int n, op, l, r, c, len;
int a[320][N];//1e5个元素,最多只需要分为317个块

int getPieceSize(int pid) {//获取第pid个块的块长。此处是计算初始块长,添加元素该函数失效
	return min(n, pid * len) - (pid - 1) * len;
}

int main() {
	IOS
	cin >> n;
	len = sqrt(n);//块长,最后一块可能不满len个元素
	int num = 1;//块数
	for (int i = 1; i <= n; ++ i) {
		cin >> a[num][i % len];
		if (i % len == 0) {
			a[num][len] = a[num][0];
			++ num;
		}	
	}
    //把每个块的元素个数存储在a[i][0]
	for (int i = 1; i <= num; ++ i) a[i][0] = getPieceSize(i);
	for (int i = 0; i < n; ++ i) {
		cin >> op >> l >> r >> c;
		if (op) {//询问 a[r] 的值
			for (int i = 1, j = 0; i <= num; ++ i) {
				if (j + a[i][0] < r) j += a[i][0];
				else {
					cout << a[i][r - j] << '\n';
					break;
				}
			}
		} else {//在第 l 个数字前插入数字 r
			for (int i = 1, j = 0; i <= num; ++ i) {
				if (j + a[i][0] < l) j += a[i][0];
				else {
					for (int k = a[i][0]; k >= l - j; -- k) a[i][k + 1] = a[i][k];
					a[i][l - j] = r;
					a[i][0] ++;
					break;
				} 
			}
		}
	}
	return 0;
}

posted on 2024-11-30 16:27  RomanLin  阅读(39)  评论(0)    收藏  举报

刷新页面返回顶部
 
博客园  ©  2004-2025
浙公网安备 33010602011771号 浙ICP备2021040463号-3