题目
题解
数据范围 \(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;
}
标签:6282,LibreOJ,分块,int,元素,len,num,sqrt
From: https://www.cnblogs.com/RomanLin/p/18560549