数列分块入门 6

分块训练

每块里面方一个vector,查询的时候找到是第几块的第几个。。

插入的话,先查询,然后在块内暴力插入。

为了防止多次在同一块插入而劣化复杂度,所以每sqrt(n)次就重新分块。。

#include <bits/stdc++.h>
#define INF 0x3f3f3f3f
#define full(a, b) memset(a, b, sizeof a)
using namespace std;
typedef long long ll;
inline int lowbit(int x){ return x & (-x); }
inline int read(){
    int X = 0, w = 0; char ch = 0;
    while(!isdigit(ch)) { w |= ch == '-'; ch = getchar(); }
    while(isdigit(ch)) X = (X << 3) + (X << 1) + (ch ^ 48), ch = getchar();
    return w ? -X : X;
}
inline int gcd(int a, int b){ return b ? gcd(b, a % b) : a; }
inline int lcm(int a, int b){ return a / gcd(a, b) * b; }
template<typename T>
inline T max(T x, T y, T z){ return max(max(x, y), z); }
template<typename T>
inline T min(T x, T y, T z){ return min(min(x, y), z); }
template<typename A, typename B, typename C>
inline A fpow(A x, B p, C lyd){
    A ans = 1;
    for(; p; p >>= 1, x = 1LL * x * x % lyd)if(p & 1)ans = 1LL * x * ans % lyd;
    return ans;
}
const int N = 100005;
vector<ll> v[1000];
ll a[N];
int n, t, m, lt[N], rt[N];

pair<int, int> query(int k){
    int x = 1;
    while(k > v[x].size())
        k -= v[x].size(), x ++;
    return make_pair(x, k - 1);
}

void reset(){
    vector<ll> all;
    for(int i = 1; i <= t; i ++){
        all.insert(all.end(), v[i].begin(), v[i].end());
        v[i].clear();
    }
    t = (int)sqrt(m);
    for(int i = 1; i <= t; i ++){
        lt[i] = (i - 1) * t + 1;
        rt[i] = i * t;
    }
    if(rt[t] < m) t ++, lt[t] = rt[t - 1] + 1, rt[t] = m;
    for(int i = 1; i <= t; i ++){
        for(int j = lt[i]; j <= rt[i]; j ++){
            v[i].push_back(all[j - 1]);
        }
    }
}

void insert(int l, ll d){
    pair<int, int> p = query(l);
    v[p.first].insert(v[p.first].begin() + p.second, d);
    m ++;
}

int main(){

    ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr);

    cin >> n; m = n;
    for(int i = 1; i <= n; i ++) cin >> a[i];
    t = (int)sqrt(n);
    for(int i = 1; i <= t; i ++){
        lt[i] = (i - 1) * t + 1;
        rt[i] = i * t;
    }
    if(rt[t] < n) t ++, lt[t] = rt[t - 1] + 1, rt[t] = n;
    for(int i = 1; i <= t; i ++){
        for(int j = lt[i]; j <= rt[i]; j ++){
            v[i].push_back(a[j]);
        }
    }
    int cnt = 0;
    for(int i = 1; i <= n; i ++){
        int opt, l; ll r, c;
        cin >> opt >> l >> r >> c;
        if(!opt) insert(l, r), cnt ++;
        else{
            pair<int, int> p = query(r);
            cout << v[p.first][p.second] << endl;
        }
        if(cnt > sqrt(m)) reset(), cnt = 0;
    }
    return 0;
}

转载于:https://www.cnblogs.com/onionQAQ/p/10877817.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值