結果

問題 No.1786 Maximum Suffix Median (Online)
ユーザー 👑 hitonanodehitonanode
提出日時 2021-12-15 03:22:01
言語 C++23(draft)
(gcc 13.2.0 + boost 1.83.0)
結果
AC  
実行時間 866 ms / 2,000 ms
コード長 15,579 bytes
コンパイル時間 2,248 ms
コンパイル使用メモリ 186,756 KB
実行使用メモリ 32,072 KB
最終ジャッジ日時 2023-10-01 02:23:06
合計ジャッジ時間 18,289 ms
ジャッジサーバーID
(参考情報)
judge15 / judge11
このコードへのチャレンジ(β)

テストケース

テストケース表示
入力 結果 実行時間
実行使用メモリ
testcase_00 AC 8 ms
22,284 KB
testcase_01 AC 8 ms
22,192 KB
testcase_02 AC 8 ms
22,116 KB
testcase_03 AC 9 ms
22,372 KB
testcase_04 AC 8 ms
22,152 KB
testcase_05 AC 8 ms
22,140 KB
testcase_06 AC 7 ms
22,092 KB
testcase_07 AC 9 ms
22,084 KB
testcase_08 AC 742 ms
26,812 KB
testcase_09 AC 496 ms
25,176 KB
testcase_10 AC 545 ms
25,476 KB
testcase_11 AC 431 ms
24,704 KB
testcase_12 AC 794 ms
27,056 KB
testcase_13 AC 531 ms
27,000 KB
testcase_14 AC 387 ms
25,376 KB
testcase_15 AC 427 ms
26,032 KB
testcase_16 AC 456 ms
26,228 KB
testcase_17 AC 360 ms
25,500 KB
testcase_18 AC 851 ms
27,320 KB
testcase_19 AC 849 ms
27,300 KB
testcase_20 AC 866 ms
27,316 KB
testcase_21 AC 848 ms
27,340 KB
testcase_22 AC 850 ms
27,400 KB
testcase_23 AC 335 ms
29,688 KB
testcase_24 AC 232 ms
27,600 KB
testcase_25 AC 414 ms
31,024 KB
testcase_26 AC 446 ms
26,172 KB
testcase_27 AC 397 ms
25,644 KB
testcase_28 AC 469 ms
26,484 KB
testcase_29 AC 9 ms
22,108 KB
testcase_30 AC 8 ms
22,076 KB
testcase_31 AC 553 ms
27,272 KB
testcase_32 AC 439 ms
32,072 KB
権限があれば一括ダウンロードができます

ソースコード

diff #

#include <algorithm>
#include <array>
#include <bitset>
#include <cassert>
#include <chrono>
#include <cmath>
#include <complex>
#include <deque>
#include <forward_list>
#include <fstream>
#include <functional>
#include <iomanip>
#include <ios>
#include <iostream>
#include <limits>
#include <list>
#include <map>
#include <numeric>
#include <queue>
#include <random>
#include <set>
#include <sstream>
#include <stack>
#include <string>
#include <tuple>
#include <type_traits>
#include <unordered_map>
#include <unordered_set>
#include <utility>
#include <vector>
using namespace std;
using lint = long long;
using pint = pair<int, int>;
using plint = pair<lint, lint>;
struct fast_ios { fast_ios(){ cin.tie(nullptr), ios::sync_with_stdio(false), cout << fixed << setprecision(20); }; } fast_ios_;
#define ALL(x) (x).begin(), (x).end()
#define FOR(i, begin, end) for(int i=(begin),i##_end_=(end);i<i##_end_;i++)
#define IFOR(i, begin, end) for(int i=(end)-1,i##_begin_=(begin);i>=i##_begin_;i--)
#define REP(i, n) FOR(i,0,n)
#define IREP(i, n) IFOR(i,0,n)
template <typename T, typename V>
void ndarray(vector<T>& vec, const V& val, int len) { vec.assign(len, val); }
template <typename T, typename V, typename... Args> void ndarray(vector<T>& vec, const V& val, int len, Args... args) { vec.resize(len), for_each(begin(vec), end(vec), [&](T& v) { ndarray(v, val, args...); }); }
template <typename T> bool chmax(T &m, const T q) { return m < q ? (m = q, true) : false; }
template <typename T> bool chmin(T &m, const T q) { return m > q ? (m = q, true) : false; }
int floor_lg(long long x) { return x <= 0 ? -1 : 63 - __builtin_clzll(x); }
template <typename T1, typename T2> pair<T1, T2> operator+(const pair<T1, T2> &l, const pair<T1, T2> &r) { return make_pair(l.first + r.first, l.second + r.second); }
template <typename T1, typename T2> pair<T1, T2> operator-(const pair<T1, T2> &l, const pair<T1, T2> &r) { return make_pair(l.first - r.first, l.second - r.second); }
template <typename T> vector<T> sort_unique(vector<T> vec) { sort(vec.begin(), vec.end()), vec.erase(unique(vec.begin(), vec.end()), vec.end()); return vec; }
template <typename T> int arglb(const std::vector<T> &v, const T &x) { return std::distance(v.begin(), std::lower_bound(v.begin(), v.end(), x)); }
template <typename T> int argub(const std::vector<T> &v, const T &x) { return std::distance(v.begin(), std::upper_bound(v.begin(), v.end(), x)); }
template <typename T> istream &operator>>(istream &is, vector<T> &vec) { for (auto &v : vec) is >> v; return is; }
template <typename T> ostream &operator<<(ostream &os, const vector<T> &vec) { os << '['; for (auto v : vec) os << v << ','; os << ']'; return os; }
template <typename T, size_t sz> ostream &operator<<(ostream &os, const array<T, sz> &arr) { os << '['; for (auto v : arr) os << v << ','; os << ']'; return os; }
#if __cplusplus >= 201703L
template <typename... T> istream &operator>>(istream &is, tuple<T...> &tpl) { std::apply([&is](auto &&... args) { ((is >> args), ...);}, tpl); return is; }
template <typename... T> ostream &operator<<(ostream &os, const tuple<T...> &tpl) { os << '('; std::apply([&os](auto &&... args) { ((os << args << ','), ...);}, tpl); return os << ')'; }
#endif
template <typename T> ostream &operator<<(ostream &os, const deque<T> &vec) { os << "deq["; for (auto v : vec) os << v << ','; os << ']'; return os; }
template <typename T> ostream &operator<<(ostream &os, const set<T> &vec) { os << '{'; for (auto v : vec) os << v << ','; os << '}'; return os; }
template <typename T, typename TH> ostream &operator<<(ostream &os, const unordered_set<T, TH> &vec) { os << '{'; for (auto v : vec) os << v << ','; os << '}'; return os; }
template <typename T> ostream &operator<<(ostream &os, const multiset<T> &vec) { os << '{'; for (auto v : vec) os << v << ','; os << '}'; return os; }
template <typename T> ostream &operator<<(ostream &os, const unordered_multiset<T> &vec) { os << '{'; for (auto v : vec) os << v << ','; os << '}'; return os; }
template <typename T1, typename T2> ostream &operator<<(ostream &os, const pair<T1, T2> &pa) { os << '(' << pa.first << ',' << pa.second << ')'; return os; }
template <typename TK, typename TV> ostream &operator<<(ostream &os, const map<TK, TV> &mp) { os << '{'; for (auto v : mp) os << v.first << "=>" << v.second << ','; os << '}'; return os; }
template <typename TK, typename TV, typename TH> ostream &operator<<(ostream &os, const unordered_map<TK, TV, TH> &mp) { os << '{'; for (auto v : mp) os << v.first << "=>" << v.second << ','; os << '}'; return os; }
#ifdef HITONANODE_LOCAL
const string COLOR_RESET = "\033[0m", BRIGHT_GREEN = "\033[1;32m", BRIGHT_RED = "\033[1;31m", BRIGHT_CYAN = "\033[1;36m", NORMAL_CROSSED = "\033[0;9;37m", RED_BACKGROUND = "\033[1;41m", NORMAL_FAINT = "\033[0;2m";
#define dbg(x) cerr << BRIGHT_CYAN << #x << COLOR_RESET << " = " << (x) << NORMAL_FAINT << " (L" << __LINE__ << ") " << __FILE__ << COLOR_RESET << endl
#define dbgif(cond, x) ((cond) ? cerr << BRIGHT_CYAN << #x << COLOR_RESET << " = " << (x) << NORMAL_FAINT << " (L" << __LINE__ << ") " << __FILE__ << COLOR_RESET << endl : cerr)
#else
#define dbg(x) (x)
#define dbgif(cond, x) 0
#endif

// Lazy randomized binary search tree
template <int LEN, class S, S (*op)(S, S), class F, S (*reversal)(S), S (*mapping)(F, S), F (*composition)(F, F), F (*id)()>
struct lazy_rbst {
    // Do your RuBeSTy! ⌒°( ・ω・)°⌒
    inline uint32_t _rand() { // XorShift
        static uint32_t x = 123456789, y = 362436069, z = 521288629, w = 88675123;
        uint32_t t = x ^ (x << 11);
        x = y;
        y = z;
        z = w;
        return w = (w ^ (w >> 19)) ^ (t ^ (t >> 8));
    }

    struct Node {
        Node *l, *r;
        S val, sum;
        F lz;
        bool is_reversed;
        int sz;
        Node(const S &v) : l(nullptr), r(nullptr), val(v), sum(v), lz(id()), is_reversed(false), sz(1) {}
        Node() : l(nullptr), r(nullptr), lz(id()), is_reversed(false), sz(0) {}
        template <class OStream> friend OStream &operator<<(OStream &os, const Node &n) {
            os << '[';
            if (n.l) os << *(n.l) << ',';
            os << n.val << ',';
            if (n.r) os << *(n.r);
            return os << ']';
        }
    };
    using Nptr = Node *;
    std::array<Node, LEN> data;
    int d_ptr;

    int size(Nptr t) const { return t != nullptr ? t->sz : 0; }

    lazy_rbst() : d_ptr(0) {}

protected:
    Nptr update(Nptr t) {
        t->sz = 1;
        t->sum = t->val;
        if (t->l) {
            t->sz += t->l->sz;
            t->sum = op(t->l->sum, t->sum);
        }
        if (t->r) {
            t->sz += t->r->sz;
            t->sum = op(t->sum, t->r->sum);
        }
        return t;
    }

    void all_apply(Nptr t, F f) {
        t->val = mapping(f, t->val);
        t->sum = mapping(f, t->sum);
        t->lz = composition(f, t->lz);
    }
    void _toggle(Nptr t) {
        auto tmp = t->l;
        t->l = t->r, t->r = tmp;
        t->sum = reversal(t->sum);
        t->is_reversed ^= true;
    }

    void push(Nptr &t) {
        _duplicate_node(t);
        if (t->lz != id()) {
            if (t->l) {
                _duplicate_node(t->l);
                all_apply(t->l, t->lz);
            }
            if (t->r) {
                _duplicate_node(t->r);
                all_apply(t->r, t->lz);
            }
            t->lz = id();
        }
        if (t->is_reversed) {
            if (t->l) _toggle(t->l);
            if (t->r) _toggle(t->r);
            t->is_reversed = false;
        }
    }

    virtual void _duplicate_node(Nptr &) {}

    Nptr _make_node(const S &val) {
        if (d_ptr >= LEN) throw;
        return &(data[d_ptr++] = Node(val));
    }

public:
    Nptr new_tree() { return nullptr; } // 新たな木を作成

    int mem_used() const { return d_ptr; }
    bool empty(Nptr t) const { return t == nullptr; }

    // lとrをrootとする木同士を結合して,新たなrootを返す
    Nptr merge(Nptr l, Nptr r) {
        if (l == nullptr or r == nullptr) return l != nullptr ? l : r;
        if (_rand() % uint32_t(l->sz + r->sz) < uint32_t(l->sz)) {
            push(l);
            l->r = merge(l->r, r);
            return update(l);
        } else {
            push(r);
            r->l = merge(l, r->l);
            return update(r);
        }
    }

    // [0, k)の木と[k, root->size())の木に分けて各root
    // (部分木の要素数が0ならnullptr)を返す
    std::pair<Nptr, Nptr> split(Nptr &root, int k) { // rootの子孫からあとk個欲しい
        if (root == nullptr) return std::make_pair(nullptr, nullptr);
        push(root);
        if (k <= size(root->l)) { // leftからk個拾える
            auto p = split(root->l, k);
            root->l = p.second;
            return std::make_pair(p.first, update(root));
        } else {
            auto p = split(root->r, k - size(root->l) - 1);
            root->r = p.first;
            return std::make_pair(update(root), p.second);
        }
    }

    // 0-indexedでarray[pos]の手前に新たな要素 x を挿入する
    void insert(Nptr &root, int pos, const S &x) {
        auto p = split(root, pos);
        root = merge(p.first, merge(_make_node(x), p.second));
    }

    // 0-indexedでarray[pos]を削除する(先頭からpos+1個目の要素)
    void erase(Nptr &root, int pos) {
        auto p = split(root, pos);
        auto p2 = split(p.second, 1);
        root = merge(p.first, p2.second);
    }

    // 1点更新 array[pos].valにupdvalを入れる
    void set(Nptr &root, int pos, const S &x) {
        auto p = split(root, pos);
        auto p2 = split(p.second, 1);
        _duplicate_node(p2.first);
        *p2.first = Node(x);
        root = merge(p.first, merge(p2.first, p2.second));
    }

    // 遅延評価を利用した範囲更新 [l, r)
    void apply(Nptr &root, int l, int r, const F &f) {
        if (l == r) return;
        auto p = split(root, l);
        auto p2 = split(p.second, r - l);
        all_apply(p2.first, f);
        root = merge(p.first, merge(p2.first, p2.second));
    }

    S prod(Nptr &root, int l, int r) {
        assert(l < r);
        auto p = split(root, l);
        auto p2 = split(p.second, r - l);
        if (p2.first != nullptr) push(p2.first);
        S res = p2.first->sum;
        root = merge(p.first, merge(p2.first, p2.second));
        return res;
    }

    // array[pos].valを取得する
    S get(Nptr &root, int pos) { return prod(root, pos, pos + 1); }

    template <bool (*g)(S)> int max_right(Nptr root, const S &e) {
        return max_right(root, e, [](S x) { return g(x); });
    }
    template <class G> int max_right(Nptr root, const S &e, G g) {
        assert(g(e));
        if (root == nullptr) return 0;
        push(root);
        Nptr now = root;
        S prod_now = e;
        int sz = 0;
        while (true) {
            if (now->l != nullptr) {
                push(now->l);
                auto pl = op(prod_now, now->l->sum);
                if (g(pl)) {
                    prod_now = pl;
                    sz += now->l->sz;
                } else {
                    now = now->l;
                    continue;
                }
            }
            auto pl = op(prod_now, now->val);
            if (!g(pl)) return sz;
            prod_now = pl, sz++;
            if (now->r == nullptr) return sz;
            push(now->r);
            now = now->r;
        }
    }

    template <bool (*g)(S)> int min_left(Nptr root, const S &e) {
        return min_left(root, e, [](S x) { return g(x); });
    }
    template <class G> int min_left(Nptr root, const S &e, G g) {
        assert(g(e));
        if (root == nullptr) return 0;
        push(root);
        Nptr now = root;
        S prod_now = e;
        int sz = size(root);
        while (true) {
            if (now->r != nullptr) {
                push(now->r);
                auto pr = op(now->r->sum, prod_now);
                if (g(pr)) {
                    prod_now = pr;
                    sz -= now->r->sz;
                } else {
                    now = now->r;
                    continue;
                }
            }
            auto pr = op(now->val, prod_now);
            if (!g(pr)) return sz;
            prod_now = pr, sz--;
            if (now->l == nullptr) return sz;
            push(now->l);
            now = now->l;
        }
    }

    void reverse(Nptr &root) { _duplicate_node(root), _toggle(root); }
    void reverse(Nptr &root, int l, int r) {
        auto p2 = split(root, r);
        auto p1 = split(p2.first, l);
        reverse(p1.second);
        root = merge(merge(p1.first, p1.second), p2.second);
    }

    // データを壊して新規にinitの内容を詰める
    void assign(Nptr &root, const std::vector<S> &init) {
        int N = init.size();
        root = N ? _assign_range(0, N, init) : new_tree();
    }
    Nptr _assign_range(int l, int r, const std::vector<S> &init) {
        if (r - l == 1) {
            Nptr t = _make_node(init[l]);
            return update(t);
        }
        return merge(_assign_range(l, (l + r) / 2, init), _assign_range((l + r) / 2, r, init));
    }

    // データをvecへ書き出し
    void dump(Nptr &t, std::vector<S> &vec) {
        if (t == nullptr) return;
        push(t);
        dump(t->l, vec);
        vec.push_back(t->val);
        dump(t->r, vec);
    }

    // gc
    void re_alloc(Nptr &root) {
        std::vector<S> mem;
        dump(root, mem);
        d_ptr = 0;
        assign(root, mem);
    }
};

using S = pint;  // [maxcnt, key]
S op(S l, S r) { return {max(l.first, r.first), max(l.second, r.second)}; }
using F = int;
S reversal(S x) { return x; }
S mapping(F f, S x) { return {x.first + f, x.second}; }
F compositon(F f, F g) { return f + g; }
F id() { return 0; }

int main() {
    int N;
    cin >> N;
    lazy_rbst<400000, S, op, F, reversal, mapping, compositon, id> rbst;
    auto root = rbst.new_tree();

    int ret;
    cin >> ret;
    cout << ret << '\n';
    vector<int> A(N);
    A[0] = ret;
    rbst.insert(root, 0, S{1, ret});

    set<int> se;
    se.insert(ret);
    FOR(i, 1, N) {
        int an;
        cin >> an;
        an ^= ret;
        A[i] = an;
        // dbg(A);
        auto k = rbst.max_right(root, pint(-1, -1), [&](S x) { return x.second <= A[i]; });
        // dbg(*root);
        // dbg(k);
        auto [ltree, rtree] = rbst.split(root, k);
        // if (ltree) dbg(*ltree);
        // if (rtree) dbg(*rtree);
        if (se.count(an)) {
            auto v = rbst.get(ltree, rbst.size(ltree) - 1);
            assert(v.second == A[i]);
            int vv = max(0, v.first);
            // if (rbst.size(rtree)) chmax(vv, rbst.get(rtree, 0).first);
            rbst.set(ltree, rbst.size(ltree) - 1, {vv, A[i]});
        } else {
            int vv = 0;
            if (rbst.size(rtree)) chmax(vv, rbst.get(rtree, 0).first);
            rbst.insert(ltree, rbst.size(ltree), S{vv, A[i]});
        }
        rbst.apply(rtree, 0, rbst.size(rtree), -1);
        rbst.apply(ltree, 0, rbst.size(ltree), 1);
        root = rbst.merge(ltree, rtree);

        se.insert(an);
        while (rbst.size(root) and rbst.get(root, rbst.size(root) - 1).first < 0) {
            se.erase(rbst.get(root, rbst.size(root) - 1).second);
            rbst.erase(root, rbst.size(root) - 1);
        }
        k = rbst.min_left(root, pint(-1, -1), [&](S x) { return x.first <= 0; }) - 1;
        ret = rbst.get(root, k).second;

        cout << ret << '\n';
    }
}
0