cplib-cpp

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

View the Project on GitHub hitonanode/cplib-cpp

:heavy_check_mark: other_algorithms/test/doubling.yuki3305.test.cpp

Depends on

Code

#define PROBLEM "https://yukicoder.me/problems/no/3305"
#include "../doubling.hpp"

#include <iostream>
#include <utility>
#include <vector>
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;

    vector<int> nexts(N, N);

    vector<pair<int, int>> st;
    st.emplace_back(N, N);
    for (int i = N - 1; i >= 0; --i) {
        while (st.back().first < A.at(i)) st.pop_back();
        nexts.at(i) = st.back().second;
        st.emplace_back(A.at(i), i);
    }

    const BinaryLifting binary_lifting(nexts);

    while (Q--) {
        int l, r;
        cin >> l >> r;
        --l;
        cout << r - l - binary_lifting.distance(l, r) << '\n';
    }
}
#line 1 "other_algorithms/test/doubling.yuki3305.test.cpp"
#define PROBLEM "https://yukicoder.me/problems/no/3305"
#line 2 "other_algorithms/doubling.hpp"
#include <cassert>
#include <vector>

// Binary lifting / `Doubling`
// Complexity: O(NlogN) precalculation / O(logN) per query
// https://atcoder.jp/contests/arc060/submissions/7039451
struct BinaryLifting {
    int N, lgD;

    bool is_valid(int idx) const { return 0 <= idx and idx < N; }

    std::vector<std::vector<int>> mat;
    BinaryLifting() : N(0), lgD(0) {}
    BinaryLifting(const std::vector<int> &to, int lgd = 0) : N(to.size()), lgD(lgd) {
        while ((1LL << lgD) < N) lgD++;
        mat.assign(lgD, std::vector<int>(N));
        mat[0] = to;

        for (int d = 0; d < lgD - 1; d++) {
            for (int i = 0; i < N; i++) {
                mat[d + 1][i] = mat[d][is_valid(mat[d][i]) ? mat[d][i] : i];
            }
        }
    }

    int kth_next(int now, long long k) const {
        assert(k >= 0);
        assert(k < (1LL << lgD));
        for (int d = 0; k and is_valid(now); d++, k >>= 1) {
            if (k & 1) now = mat[d][now];
        }
        return now;
    }

    // Distance from l to [r, \infty)
    // Requirement: mat[0][i] >= r (i = r, r + 1, ...) (monotone)
    int distance(int l, int r) const {
        if (l >= r) return 0;
        int ret = 0;
        for (int d = lgD - 1; d >= 0; d--) {
            if (mat[d][l] < r and is_valid(mat[d][l])) ret += 1 << d, l = mat[d][l];
        }

        if (!is_valid(mat[0][l]) or mat[0][l] >= r) {
            return ret + 1;
        } else {
            return -1; // Unable to reach
        }
    }
};
#line 3 "other_algorithms/test/doubling.yuki3305.test.cpp"

#include <iostream>
#include <utility>
#line 7 "other_algorithms/test/doubling.yuki3305.test.cpp"
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;

    vector<int> nexts(N, N);

    vector<pair<int, int>> st;
    st.emplace_back(N, N);
    for (int i = N - 1; i >= 0; --i) {
        while (st.back().first < A.at(i)) st.pop_back();
        nexts.at(i) = st.back().second;
        st.emplace_back(A.at(i), i);
    }

    const BinaryLifting binary_lifting(nexts);

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