cplib-cpp

This documentation is automatically generated by online-judge-tools/verification-helper

View the Project on GitHub hitonanode/cplib-cpp

:heavy_check_mark: data_structure/test/static_range_inversion.test.cpp

Depends on

Code

#include "../static_range_inversion.hpp"
#define PROBLEM "https://judge.yosupo.jp/problem/static_range_inversions_query"

#include <iostream>
using namespace std;

int main() {
    cin.tie(nullptr), ios::sync_with_stdio(false);
    int N, Q;
    cin >> N >> Q;
    vector<int> A(N);
    for (auto &a : A) cin >> a;
    StaticRangeInversion<int> riq(A);

    while (Q--) {
        int l, r;
        cin >> l >> r;
        cout << riq.get(l, r) << '\n';
    }
}
#line 2 "data_structure/static_range_inversion.hpp"
#include <algorithm>
#include <cassert>
#include <cmath>
#include <utility>
#include <vector>

// CUT begin
// Static Range Inversion Query (Online)
// Complexity: O((N + Q)sqrt(N)) time, O(Nsqrt(N)) space (~128MB for N=1e5)
// Reference: <https://stackoverflow.com/questions/21763392/counting-inversions-in-ranges>
template <typename T> struct StaticRangeInversion {
    const int N;
    const int bs;    // bucket size
    const int nb_bc; // # of buckets
    std::vector<int> vals;
    std::vector<std::pair<int, int>> vals_sorted;
    std::vector<std::vector<int>> presuf;
    std::vector<int> sufG, preH;
    std::vector<std::vector<long long>> R;

    StaticRangeInversion(const std::vector<T> &sequence)
        : N(sequence.size()), bs(ceil(sqrt(std::max(N, 1)))), nb_bc((N + bs - 1) / bs) {
        std::vector<T> dict = sequence;
        std::sort(dict.begin(), dict.end()),
            dict.erase(std::unique(dict.begin(), dict.end()), dict.end());
        const int D = dict.size();
        vals.reserve(N), vals_sorted.reserve(N);
        for (auto x : sequence) {
            vals.emplace_back(std::lower_bound(dict.begin(), dict.end(), x) - dict.begin());
            vals_sorted.emplace_back(vals.back(), int(vals.size()) - 1);
        }

        presuf.assign(nb_bc, std::vector<int>(N));
        sufG.resize(N), preH.resize(N);

        for (int ibc = 0; ibc < nb_bc; ibc++) {
            const int L = ibc * bs, R = std::min(L + bs, N);
            std::sort(vals_sorted.begin() + L, vals_sorted.begin() + R);
            std::vector<int> cnt(D + 1);
            for (int i = L; i < R; i++) { cnt[vals[i] + 1]++; }
            for (int i = 0; i < D; i++) { cnt[i + 1] += cnt[i]; }
            for (int b = 0; b < ibc; b++) {
                for (int i = (b + 1) * bs - 1; i >= b * bs; i--) {
                    presuf[ibc][i] = presuf[ibc][i + 1] + cnt[vals[i]];
                }
            }
            for (int b = ibc + 1; b < bs; b++) {
                for (int i = b * bs; i < std::min((b + 1) * bs, N); i++) {
                    presuf[ibc][i] =
                        (i == b * bs ? 0 : presuf[ibc][i - 1]) + cnt.back() - cnt[vals[i] + 1];
                }
            }
            for (int i = L + 1; i < R; i++) {
                preH[i] = preH[i - 1] + std::count_if(vals.begin() + L, vals.begin() + i,
                                                      [&](int x) { return x > vals[i]; });
            }
            for (int i = R - 2; i >= L; i--) {
                sufG[i] = sufG[i + 1] + std::count_if(vals.begin() + i + 1, vals.begin() + R,
                                                      [&](int x) { return x < vals[i]; });
            }
        }

        R.resize(nb_bc, std::vector<long long>(nb_bc));
        for (int i = nb_bc - 1; i >= 0; i--) {
            R[i][i] = sufG[i * bs];
            for (int j = i + 1; j < nb_bc; j++) {
                R[i][j] = R[i][j - 1] + R[i + 1][j] - R[i + 1][j - 1] + presuf[j][i * bs];
            }
        }
    }
    long long get(int l, int r) const {
        assert(l >= 0 and l <= N and r >= 0 and r <= N and l <= r);
        const int lb = (l + bs - 1) / bs, rb = (r == N ? nb_bc : r / bs) - 1;
        long long ret = 0;
        if (l / bs == (r - 1) / bs) {
            const int b = l / bs;
            ret += preH[r - 1] - (l % bs ? preH[l - 1] : 0);
            int less_cnt = 0;
            for (int p = b * bs, q = std::min((b + 1) * bs, N); p < q; p++) {
                less_cnt += (vals_sorted[p].second >= l and vals_sorted[p].second < r);
                ret -= less_cnt * (vals_sorted[p].second < l);
            }
            return ret;
        }
        ret += R[lb][rb];
        if (bs * lb > l) {
            ret += sufG[l];
            for (int b = lb; b <= rb; b++) { ret += presuf[b][l]; }
        }
        if (bs * (rb + 1) < r) {
            ret += preH[r - 1];
            for (int b = lb; b <= rb; b++) { ret += presuf[b][r - 1]; }
        }
        int less_cnt = 0, j = (rb + 1) * bs;
        for (int p = std::max(0, (lb - 1) * bs), q = lb * bs; p < q; p++) {
            if (vals_sorted[p].second >= l) {
                while (j < std::min(N, (rb + 2) * bs) and
                       (vals_sorted[j].second >= r or vals_sorted[j].first < vals_sorted[p].first)) {
                    less_cnt += (vals_sorted[j].second < r), j++;
                }
                ret += less_cnt;
            }
        }
        return ret;
    }
};
#line 2 "data_structure/test/static_range_inversion.test.cpp"
#define PROBLEM "https://judge.yosupo.jp/problem/static_range_inversions_query"

#include <iostream>
using namespace std;

int main() {
    cin.tie(nullptr), ios::sync_with_stdio(false);
    int N, Q;
    cin >> N >> Q;
    vector<int> A(N);
    for (auto &a : A) cin >> a;
    StaticRangeInversion<int> riq(A);

    while (Q--) {
        int l, r;
        cin >> l >> r;
        cout << riq.get(l, r) << '\n';
    }
}
Back to top page