結果

問題 No.3671 Reusable Lazy Segment Tree
コンテスト
ユーザー harurun
提出日時 2026-08-17 22:15:43
言語 C++23(gcc16)
(gcc 16.1.0 + boost 1.92.0 + ACL)
コンパイル:
g++-16 -O2 -lm -std=c++23 -Wuninitialized -DONLINE_JUDGE -o a.out _filename_
実行:
./a.out
結果
AC  
実行時間 5,227 ms / 6,000 ms
+ 431µs
コード長 19,838 bytes
記録
記録タグの例:
初AC ショートコード 純ショートコード 純主流ショートコード 最速実行時間
コンパイル時間 2,733 ms
コンパイル使用メモリ 368,880 KB
実行使用メモリ 70,912 KB
最終ジャッジ日時 2026-09-04 22:27:35
合計ジャッジ時間 33,420 ms
ジャッジサーバーID
(参考情報)
judge1_0 / judge2_0
このコードへのチャレンジ
(要ログイン)
ファイルパターン 結果
sample AC * 1
other AC * 19
権限があれば一括ダウンロードができます

ソースコード

diff #
raw source code

#include <bits/stdc++.h>
#line 1 "src/structure/segtree/rollback/rollback_lazysegtree.hpp"



#include <array>
#include <cstddef>
#include <functional>
#include <limits>
#include <optional>
#include <stdexcept>
#include <type_traits>
#include <utility>
#include <vector>
#line 1 "src/structure/types/monoid/monoid_act.hpp"


#line 1 "src/structure/types/monoid/monoid.hpp"



#line 5 "src/structure/types/monoid/monoid.hpp"

template<auto op_func, auto e_func>
struct Monoid{
    using S = std::decay_t<decltype(e_func())>;
    constexpr S op(S a, S b)const{
        return op_func(a,b);
    }
    constexpr S e()const{
        return e_func();
    }
};


#line 4 "src/structure/types/monoid/monoid_act.hpp"

template<auto op_func, auto e_func, auto mapping_func, auto composition_func, auto id_func>
struct Monoid_Act: Monoid<op_func,e_func>{
    using S = std::decay_t<decltype(e_func())>;
    using T = std::decay_t<decltype(id_func())>;
    constexpr S mapping(T f, S x)const{
        return mapping_func(f, x);
    }
    constexpr T composition(T f, T g)const{
        return composition_func(f, g);
    }
    constexpr T id()const{
        return id_func();
    }
};


#line 14 "src/structure/segtree/rollback/rollback_lazysegtree.hpp"

template<auto Monoid_act, int MAX_SIZE, int MAX_UPDATE>
struct RollbackLazySegtree{
    static_assert(MAX_SIZE > 0);
    static_assert(MAX_UPDATE >= 0);

    using S = typename std::remove_cvref_t<decltype(Monoid_act)>::S;
    using T = typename std::remove_cvref_t<decltype(Monoid_act)>::T;
    using Snapshot = int;

    static constexpr int sz = []{
        int res = 1;
        while(res < MAX_SIZE){
            res <<= 1;
        }
        return res;
    }();

    static constexpr int height = []{
        int res = 1;
        int h = 0;
        while(res < MAX_SIZE){
            res <<= 1;
            h++;
        }
        return h;
    }();

private:
    static constexpr std::size_t changes_per_update =
        static_cast<std::size_t>(8 * height) + 4;

    static_assert(
        static_cast<std::size_t>(MAX_UPDATE) <=
        std::numeric_limits<std::size_t>::max() / changes_per_update
    );

    static constexpr std::size_t history_capacity =
        static_cast<std::size_t>(MAX_UPDATE) * changes_per_update;

    struct DataHistory{
        int index;
        S value;
    };

    struct LazyHistory{
        int index;
        T value;
    };

    struct Operation{
        int data_size;
        int lazy_size;
    };

    int _n = 0;
    int operation_count = 0;
    int data_history_size = 0;
    int lazy_history_size = 0;

    std::array<S, 2 * sz> data;
    std::array<T, sz> lazy;
    std::array<std::optional<DataHistory>, history_capacity> data_history;
    std::array<std::optional<LazyHistory>, history_capacity> lazy_history;
    std::array<Operation, MAX_UPDATE> operation_history;

    void initialize(int n){
        if(n < 0 || MAX_SIZE < n)[[unlikely]]{
            throw std::runtime_error(
                "library assertion fault: range violation (constructor)."
            );
        }
        _n = n;
        data.fill(Monoid_act.e());
        lazy.fill(Monoid_act.id());
    }

    void build(){
        for(int k = sz - 1; k > 0; k--){
            data[k] = Monoid_act.op(data[2 * k], data[2 * k + 1]);
        }
    }

    void write_data(int k, const S& value){
        if(
            static_cast<std::size_t>(data_history_size) >= history_capacity
        )[[unlikely]]{
            throw std::runtime_error(
                "library assertion fault: history capacity exceeded (update)."
            );
        }
        data_history[data_history_size].emplace(DataHistory{k, data[k]});
        data[k] = value;
        data_history_size++;
    }

    void write_lazy(int k, const T& value){
        if(
            static_cast<std::size_t>(lazy_history_size) >= history_capacity
        )[[unlikely]]{
            throw std::runtime_error(
                "library assertion fault: history capacity exceeded (update)."
            );
        }
        lazy_history[lazy_history_size].emplace(LazyHistory{k, lazy[k]});
        lazy[k] = value;
        lazy_history_size++;
    }

    void restore(Operation snapshot){
        while(snapshot.data_size < data_history_size){
            --data_history_size;
            const auto& entry = *data_history[data_history_size];
            data[entry.index] = entry.value;
            data_history[data_history_size].reset();
        }
        while(snapshot.lazy_size < lazy_history_size){
            --lazy_history_size;
            const auto& entry = *lazy_history[lazy_history_size];
            lazy[entry.index] = entry.value;
            lazy_history[lazy_history_size].reset();
        }
    }

    void update(int k){
        S value = Monoid_act.op(data[2 * k], data[2 * k + 1]);
        write_data(k, value);
    }

    void all_apply(int k, const T& f){
        S value = Monoid_act.mapping(f, data[k]);
        if(k < sz){
            T action = Monoid_act.composition(f, lazy[k]);
            write_data(k, value);
            write_lazy(k, action);
        }else{
            write_data(k, value);
        }
    }

    void push(int k){
        T action = lazy[k];

        if (action == Monoid_act.id()) return;

        all_apply(2 * k, action);
        all_apply(2 * k + 1, action);
        write_lazy(k, Monoid_act.id());
    }

    void set_impl(int k, int l, int r, int p, const S& x){
        if(r - l == 1){
            write_data(k, x);
            return;
        }
        push(k);
        int mid = l + (r - l) / 2;
        if(p < mid){
            set_impl(2 * k, l, mid, p, x);
        }else{
            set_impl(2 * k + 1, mid, r, p, x);
        }
        update(k);
    }

    void apply_impl(
        int k,
        int l,
        int r,
        int ql,
        int qr,
        const T& f
    ){
        if(ql <= l && r <= qr){
            all_apply(k, f);
            return;
        }
        push(k);
        int mid = l + (r - l) / 2;
        if(ql < mid){
            apply_impl(2 * k, l, mid, ql, qr, f);
        }
        if(mid < qr){
            apply_impl(2 * k + 1, mid, r, ql, qr, f);
        }
        update(k);
    }

    S prod_impl(
        int k,
        int l,
        int r,
        int ql,
        int qr,
        const T& carry
    ) const{
        if(r <= ql || qr <= l){
            return Monoid_act.e();
        }
        if(ql <= l && r <= qr){
            return Monoid_act.mapping(carry, data[k]);
        }
        T next = k < sz
            ? Monoid_act.composition(carry, lazy[k])
            : carry;
        int mid = l + (r - l) / 2;
        return Monoid_act.op(
            prod_impl(2 * k, l, mid, ql, qr, next),
            prod_impl(2 * k + 1, mid, r, ql, qr, next)
        );
    }

    template<class F, class... Args>
    int max_right_impl(
        int k,
        int l,
        int r,
        int ql,
        const T& carry,
        S& sm,
        F& f,
        Args&... args
    ) const{
        if(r <= ql || _n <= l){
            return -1;
        }
        if(ql <= l && r <= _n){
            S value = Monoid_act.mapping(carry, data[k]);
            S next_value = Monoid_act.op(sm, value);
            if(std::invoke(f, next_value, args...)){
                sm = next_value;
                return -1;
            }
            if(r - l == 1){
                return l;
            }
        }
        T next = k < sz
            ? Monoid_act.composition(carry, lazy[k])
            : carry;
        int mid = l + (r - l) / 2;
        int res = max_right_impl(
            2 * k, l, mid, ql, next, sm, f, args...
        );
        if(res != -1){
            return res;
        }
        return max_right_impl(
            2 * k + 1, mid, r, ql, next, sm, f, args...
        );
    }

    template<class F, class... Args>
    int min_left_impl(
        int k,
        int l,
        int r,
        int qr,
        const T& carry,
        S& sm,
        F& f,
        Args&... args
    ) const{
        if(qr <= l || _n <= l){
            return -1;
        }
        if(r <= qr && r <= _n){
            S value = Monoid_act.mapping(carry, data[k]);
            S next_value = Monoid_act.op(value, sm);
            if(std::invoke(f, next_value, args...)){
                sm = next_value;
                return -1;
            }
            if(r - l == 1){
                return r;
            }
        }
        T next = k < sz
            ? Monoid_act.composition(carry, lazy[k])
            : carry;
        int mid = l + (r - l) / 2;
        int res = min_left_impl(
            2 * k + 1, mid, r, qr, next, sm, f, args...
        );
        if(res != -1){
            return res;
        }
        return min_left_impl(
            2 * k, l, mid, qr, next, sm, f, args...
        );
    }

    template<class F>
    void perform_update(F&& update_function){
        if(operation_count == MAX_UPDATE)[[unlikely]]{
            throw std::runtime_error(
                "library assertion fault: capacity violation (update)."
            );
        }
        Operation snapshot{data_history_size, lazy_history_size};
        try{
            std::forward<F>(update_function)();
        }catch(...){
            restore(snapshot);
            throw;
        }
        operation_history[operation_count++] = snapshot;
    }

public:
    RollbackLazySegtree(const RollbackLazySegtree&) = delete;
    RollbackLazySegtree& operator=(const RollbackLazySegtree&) = delete;
    RollbackLazySegtree(RollbackLazySegtree&&) = delete;
    RollbackLazySegtree& operator=(RollbackLazySegtree&&) = delete;

    explicit RollbackLazySegtree(int n = MAX_SIZE){
        initialize(n);
        build();
    }

    explicit RollbackLazySegtree(const std::vector<S>& v){
        if(v.size() > static_cast<std::size_t>(MAX_SIZE))[[unlikely]]{
            throw std::runtime_error(
                "library assertion fault: range violation (constructor)."
            );
        }
        initialize(static_cast<int>(v.size()));
        for(int k = 0; k < _n; k++){
            data[k + sz] = v[static_cast<std::size_t>(k)];
        }
        build();
    }

    template<std::size_t N>
    explicit RollbackLazySegtree(const std::array<S, N>& v){
        if(N > static_cast<std::size_t>(MAX_SIZE))[[unlikely]]{
            throw std::runtime_error(
                "library assertion fault: range violation (constructor)."
            );
        }
        initialize(static_cast<int>(N));
        for(int k = 0; k < _n; k++){
            data[k + sz] = v[static_cast<std::size_t>(k)];
        }
        build();
    }

    int size() const{
        return _n;
    }

    int history_size() const{
        return operation_count;
    }

    bool can_undo() const{
        return operation_count != 0;
    }

    void set(int k, const S& x){
        if(k < 0 || _n <= k)[[unlikely]]{
            throw std::runtime_error(
                "library assertion fault: range violation (set)."
            );
        }
        perform_update([&]{
            set_impl(1, 0, sz, k, x);
        });
    }

    void apply(int k, const T& f){
        if(k < 0 || _n <= k)[[unlikely]]{
            throw std::runtime_error(
                "library assertion fault: range violation (apply)."
            );
        }
        perform_update([&]{
            apply_impl(1, 0, sz, k, k + 1, f);
        });
    }

    void apply(int l, int r, const T& f){
        if(l < 0 || r < l || _n < r)[[unlikely]]{
            throw std::runtime_error(
                "library assertion fault: range violation (apply)."
            );
        }
        perform_update([&]{
            if(l != r){
                apply_impl(1, 0, sz, l, r, f);
            }
        });
    }

    S get(int k) const{
        if(k < 0 || _n <= k)[[unlikely]]{
            throw std::runtime_error(
                "library assertion fault: range violation (get)."
            );
        }
        return prod_impl(1, 0, sz, k, k + 1, Monoid_act.id());
    }

    S prod(int l, int r) const{
        if(l < 0 || r < l || _n < r)[[unlikely]]{
            throw std::runtime_error(
                "library assertion fault: range violation (prod)."
            );
        }
        return prod_impl(1, 0, sz, l, r, Monoid_act.id());
    }

    S all_prod() const{
        return data[1];
    }

    int max_right(int l, auto f, auto&&... args) const{
        if(l < 0 || _n < l)[[unlikely]]{
            throw std::runtime_error(
                "library assertion fault: range violation (max_right)."
            );
        }
        if(!std::invoke(f, Monoid_act.e(), args...))[[unlikely]]{
            throw std::runtime_error(
                "library assertion fault: f(e) must be true (max_right)."
            );
        }
        if(l == _n){
            return _n;
        }
        S sm = Monoid_act.e();
        int res = max_right_impl(
            1, 0, sz, l, Monoid_act.id(), sm, f, args...
        );
        return res == -1 ? _n : res;
    }

    int min_left(int r, auto f, auto&&... args) const{
        if(r < 0 || _n < r)[[unlikely]]{
            throw std::runtime_error(
                "library assertion fault: range violation (min_left)."
            );
        }
        if(!std::invoke(f, Monoid_act.e(), args...))[[unlikely]]{
            throw std::runtime_error(
                "library assertion fault: f(e) must be true (min_left)."
            );
        }
        if(r == 0){
            return 0;
        }
        S sm = Monoid_act.e();
        int res = min_left_impl(
            1, 0, sz, r, Monoid_act.id(), sm, f, args...
        );
        return res == -1 ? 0 : res;
    }

    Snapshot snapshot() const{
        return operation_count;
    }

    void undo(){
        if(!can_undo())[[unlikely]]{
            throw std::runtime_error(
                "library assertion fault: undo history is empty (undo)."
            );
        }
        --operation_count;
        restore(operation_history[operation_count]);
    }

    void rollback(Snapshot snapshot){
        if(snapshot < 0 || operation_count < snapshot)[[unlikely]]{
            throw std::runtime_error(
                "library assertion fault: range violation (rollback)."
            );
        }
        while(snapshot < operation_count){
            undo();
        }
    }
};



using namespace std;

using U32 = uint32_t;
using U64 = uint64_t;

static constexpr int BITS = 30;
static constexpr U32 VALUE_MASK = (U32(1) << BITS) - 1;

// 問題の制約に合わせて設定
static constexpr int MAX_N = 100000;
static constexpr int MAX_UPDATE = 1000;


// ============================================================
// RollbackLazySegtree 用の作用付きモノイド
// ============================================================

// 各 bit が区間内で何個立っているかを保持する。
struct BitCount {
    array<U32, BITS> cnt{};
    U32 len = 0;
};

// 作用
//
// value -> (value & and_mask) | or_mask
struct BitAction {
    U32 and_mask;
    U32 or_mask;

    friend bool operator==(const BitAction&, const BitAction&) = default;
};


// 区間のマージ
BitCount op(BitCount a, BitCount b) {
    BitCount res;
    res.len = a.len + b.len;

    for (int bit = 0; bit < BITS; ++bit) {
        res.cnt[bit] = a.cnt[bit] + b.cnt[bit];
    }

    return res;
}


// 単位元
BitCount e() {
    return {};
}


// 作用を区間情報に適用
BitCount mapping(BitAction f, BitCount x) {
    for (int bit = 0; bit < BITS; ++bit) {
        const U32 bit_mask = U32(1) << bit;

        if (f.or_mask & bit_mask) {
            // OR によってこの bit は全要素で 1
            x.cnt[bit] = x.len;
        } else if ((f.and_mask & bit_mask) == 0) {
            // AND によってこの bit は全要素で 0
            x.cnt[bit] = 0;
        }
    }

    return x;
}


// f(g(x)) を表す作用を返す。
BitAction composition(BitAction f, BitAction g) {
    // g:
    //   (x & g.and_mask) | g.or_mask
    //
    // その後 f:
    //   (((x & g.and_mask) | g.or_mask) & f.and_mask)
    //       | f.or_mask
    //
    // =
    //   (x & g.and_mask & f.and_mask)
    //       | (g.or_mask & f.and_mask)
    //       | f.or_mask

    return {
        g.and_mask & f.and_mask,
        (g.or_mask & f.and_mask) | f.or_mask
    };
}


// 恒等作用
BitAction id() {
    return {VALUE_MASK, 0};
}


constexpr Monoid_Act<
    op,
    e,
    mapping,
    composition,
    id
> bitwise_monoid_act{};


// 1要素から BitCount を作る。
BitCount make_value(U32 value) {
    BitCount res;
    res.len = 1;

    value &= VALUE_MASK;

    for (int bit = 0; bit < BITS; ++bit) {
        res.cnt[bit] = (value >> bit) & 1U;
    }

    return res;
}


// BitCount から区間和を求める。
U64 get_sum(const BitCount& x) {
    U64 res = 0;

    for (int bit = 0; bit < BITS; ++bit) {
        res += static_cast<U64>(x.cnt[bit]) << bit;
    }

    return res;
}


// OR 作用
BitAction make_or(U32 mask) {
    mask &= VALUE_MASK;
    return {VALUE_MASK, mask};
}


// AND 作用
BitAction make_and(U32 mask) {
    mask &= VALUE_MASK;
    return {mask, 0};
}


static int clamp_index(U32 value, int n) {
    if (value < 1) return 1;
    if (value > static_cast<U32>(n)) return n;
    return static_cast<int>(value);
}


int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    int N, M;
    cin >> N >> M;

    vector<U32> A(N);
    for (auto& value : A) {
        cin >> value;
    }

    vector<U32> l(M + 1);
    vector<U32> r(M + 1);
    vector<U32> x(M + 1);
    vector<U32> L(M + 1);
    vector<U32> R(M + 1);

    for (int i = 1; i <= M; ++i) cin >> l[i];
    for (int i = 1; i <= M; ++i) cin >> r[i];
    for (int i = 1; i <= M; ++i) cin >> x[i];
    for (int i = 1; i <= M; ++i) cin >> L[i];
    for (int i = 1; i <= M; ++i) cin >> R[i];


    // RollbackLazySegtree の初期値を構築
    vector<BitCount> initial(N);

    for (int i = 0; i < N; ++i) {
        initial[i] = make_value(A[i]);
    }


    using Segtree = RollbackLazySegtree<
        bitwise_monoid_act,
        MAX_N,
        MAX_UPDATE
    >;

    // RollbackLazySegtree は内部に大きな std::array を持つので heap に置く。
    auto seg = make_unique<Segtree>(initial);


    int Q;
    cin >> Q;

    for (int i = 1; i <= Q; ++i) {
        int s, q;
        cin >> s >> q;

        // この時点の状態を保存
        const auto snapshot = seg->snapshot();

        U32 y = static_cast<U32>(i);

        for (int j = 1; j <= q; ++j) {
            const int z = ((s + j) % M) + 1;

            const int u = clamp_index(l[z] ^ y, N);
            const int v = clamp_index(r[z] ^ y, N);

            const int ql = min(u, v) - 1;
            const int qr = max(u, v) - 1;


            const int big_u = clamp_index(L[z] ^ y, N);
            const int big_v = clamp_index(R[z] ^ y, N);

            const int sum_l = min(big_u, big_v) - 1;
            const int sum_r = max(big_u, big_v) - 1;


            const U32 mask = (x[z] ^ y) & VALUE_MASK;

            // RollbackLazySegtree は [l, r) なので qr + 1
            if ((z & 1) == 0) {
                seg->apply(
                    ql,
                    qr + 1,
                    make_or(mask)
                );
            } else {
                seg->apply(
                    ql,
                    qr + 1,
                    make_and(mask)
                );
            }


            // prod も [l, r)
            const BitCount result = seg->prod(
                sum_l,
                sum_r + 1
            );

            y = static_cast<U32>(get_sum(result)) & VALUE_MASK;
        }

        cout << y << '\n';

        // このクエリ中の全 apply を取り消す
        seg->rollback(snapshot);
    }

    return 0;
}
0