😊 | Powered By HeartFireY | 分块例题

​#6282. 数列分块入门 6 - 题目 - LibreOJ (loj.ac)​

给出一个长为6.数列分块入门 6_数据结构的数列,以及6.数列分块入门 6_数据结构个操作,操作涉及单点插入,单点询问,数据随机生成。

由于操作涉及单点插入,因此分块的长度会发生变化,因此采用6.数列分块入门 6_分块_03储存每个分块的数据,在更新的时将数据暴力取出更新后放回,对分块结构进行重构。

需要注意的是,并不是每次更新都需要重构,只需要在某个分块的6.数列分块入门 6_数据结构_04变得非常大时,我们才对分块进行暴力重构。如果变动不大,我们可以近似认为每个分块均摊插入后的6.数列分块入门 6_数据结构_04

#include <bits/stdc++.h>
#define ll int
#define pii pair<int, int>
using namespace std;

const int N = 200005;
int blo, lst;
ll a[N], tmp_storage[N];
vector<int> block[N];

void refresh(){
int tot = 0;
for(int i = 1; i <= lst; i++){
for(auto i : block[i]) tmp_storage[++tot] = i;
block[i].clear();
}
blo = sqrt(tot);
for(int i = 1; i <= tot; i++){
int id = (i - 1) / blo + 1;
block[id].push_back(tmp_storage[i]);
}
lst = (tot - 1) / blo + 1;
}

pii query(int pos, int now = 1){
while(pos > block[now].size()){
pos -= block[now].size();
now++;
}
return make_pair(now, pos - 1);
}

void insert(int pos, int x){
pii tmp = query(pos);
block[tmp.first].insert(block[tmp.first].begin() + tmp.second, x);
if(block[tmp.first].size() > 20 * blo) refresh();
}

inline int read(){
int f = 1, x = 0; char s = getchar();
while(s < '0'||s > '9'){ if(s =='-') f = -1; s = getchar(); }
while(s >= '0' && s <= '9'){ x = x * 10 + s - '0'; s = getchar();}
return x *= f;
}

signed main(){
int n = read();; blo = sqrt(n);
for(int i = 1; i <= n; i++) cin >> a[i];
for(int i = 1; i <= n; i++) block[(i - 1) / blo + 1].push_back(a[i]);
lst = (n - 1) / blo + 1;
for(int i = 1; i <= n; i++){
int op = read(), l = read(), r = read(), c = read();
if(op == 0) insert(l, r);
else{
pii tmp = query(r);
printf("%d\n", block[tmp.first][tmp.second]);
}
}
return 0;
}