LOJ数列分块入门 6 题解 重新分块(重构)

题目链接:https://loj.ac/p/6282

涉及操作:

  1. 单点插入;
  2. 单调询问。

解题思路:

\(\sqrt n\) 次插入后,重新把数列平均分一下,重构需要的时间复杂度为 \(O(n)\),重构的次数为 \(O(\sqrt n)\),可以解决这个问题。

但是按照原作者的代码,是:如果出现某个分块的大小大于初始分块大小的 \(20\) 倍时,再重新分块。这里按照这种写法。

示例程序:

#include <bits/stdc++.h>
using namespace std;
int n, m, blo, a;
vector<int> vec[1010], tmp;

void rebuild() {
    tmp.clear();
    for (int i = 1; i <= m; i ++) {
        for (auto x : vec[i])
            tmp.push_back(x);
        vec[i].clear();
    }
    int sz = tmp.size();
    int blo2 = sqrt(sz);
    for (int i = 0; i < sz; i ++)
        vec[i/blo2+1].push_back(tmp[i]);
    m = (sz - 1) / blo2 + 1;
}
pair<int, int> query(int p) {
    int x = 1;
    while (vec[x].size() < p) {
        p -= vec[x].size();
        x ++;
    }
    return { x, p-1 };
}
void add(int p, int val) {
    pair<int, int> pi = query(p);
    int x = pi.first, y = pi.second;
    vec[x].insert(vec[x].begin() + y, val);
    if (vec[x].size() > 20*blo)
        rebuild();
}

int main() {
    ios::sync_with_stdio(0);
    cin >> n;
    blo = sqrt(n);
    for (int i = 1; i <= n; i ++) {
        cin >> a;
        vec[(i-1)/blo+1].push_back(a);
    }
    m = (n - 1) / blo + 1;
    for (int i = 0; i < n; i ++) {
        int op, l, r, c;
        cin >> op >> l >> r >> c;
        if (op == 0) add(l, r);
        else {
            pair<int, int> pi = query(r);
            int x = pi.first, y = pi.second;
            cout << vec[x][y] << endl;
        }
    }
    return 0;
}
posted @ 2021-11-08 21:07  quanjun  阅读(80)  评论(0编辑  收藏  举报