library

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

View the Project on GitHub maspypy/library

:heavy_check_mark: test/3_yukicoder/2809.test.cpp

Depends on

Code

#define PROBLEM "https://yukicoder.me/problems/no/2809"
#include "my_template.hpp"
#include "other/io.hpp"

#include "ds/sortable_array.hpp"

void solve() {
  LL(N, Q);
  VEC(ll, A, N);
  vc<tuple<ll, ll, ll>> query;
  vi X = A;
  FOR(Q) {
    INT(t);
    if (t == 1) {
      LL(k, x);
      query.eb(t, --k, x);
      X.eb(x);
    }
    if (t == 2) { query.eb(t, -1, -1); }
    if (t == 3) {
      LL(k);
      query.eb(t, --k, -1);
    }
  }
  UNIQUE(X);
  for (auto& x: A) x = LB(X, x);

  vc<int> now(N);
  FOR(i, N) now[i] = A[i];
  Sortable_Array SA(20000000, len(X), now);

  for (auto& [t, k, x]: query) {
    if (t == 1) {
      x = LB(X, x);
      SA.set(k, x);
    }
    if (t == 2) { SA.sort_inc(0, N); }
    if (t == 3) {
      ll x = SA.get(k);
      print(X[x]);
    }
  }
}

signed main() {
  int T = 1;
  // INT(T);
  FOR(T) solve();
  return 0;
}
#line 1 "test/3_yukicoder/2809.test.cpp"
#define PROBLEM "https://yukicoder.me/problems/no/2809"
#line 1 "my_template.hpp"
// Source: https://github.com/maspypy/library/blob/main/my_template.hpp
#if defined(USE_PCH)
#include <my_template_compiled.hpp>

#if defined(__GNUC__)
#pragma GCC optimize("Ofast,unroll-loops")
#if !defined(MASPY_NON_AVX2)
#pragma GCC target("avx2,popcnt")
#endif
#endif
#else  // MASPY_TEMPLATE_BODY
#include <bits/stdc++.h>
#include <cassert>

using namespace std;

using ll = long long;
using u8 = uint8_t;
using u16 = uint16_t;
using u32 = uint32_t;
using u64 = uint64_t;
using i128 = __int128;
using u128 = unsigned __int128;
using f128 = __float128;

template <class>
constexpr bool dependent_false = false;

template <class T>
constexpr T infty = [] {
  static_assert(dependent_false<T>, "infty<T> is not defined");
  return T{};
}();
template <>
constexpr int infty<int> = 1'010'000'000;
template <>
constexpr ll infty<ll> = 2'020'000'000'000'000'000;
template <>
constexpr u32 infty<u32> = infty<int>;
template <>
constexpr u64 infty<u64> = infty<ll>;
template <>
constexpr i128 infty<i128> = i128(infty<ll>) * 2'000'000'000'000'000'000;
template <>
constexpr double infty<double> = infty<i128>;
template <>
constexpr long double infty<long double> = infty<i128>;

using pi = pair<ll, ll>;
using vi = vector<ll>;
template <class T>
using vc = vector<T>;
template <class T>
using vvc = vector<vc<T>>;
template <class T>
using vvvc = vector<vvc<T>>;
template <class T>
using vvvvc = vector<vvvc<T>>;
template <class T>
using pq_max = priority_queue<T>;
template <class T>
using pq_min = priority_queue<T, vector<T>, greater<T>>;

#define vv(type, name, h, ...) \
  vector<vector<type>> name(h, vector<type>(__VA_ARGS__))
#define vvv(type, name, h, w, ...)   \
  vector<vector<vector<type>>> name( \
      h, vector<vector<type>>(w, vector<type>(__VA_ARGS__)))
#define vvvv(type, name, a, b, c, ...)       \
  vector<vector<vector<vector<type>>>> name( \
      a, vector<vector<vector<type>>>(       \
             b, vector<vector<type>>(c, vector<type>(__VA_ARGS__))))

// https://trap.jp/post/1224/
#define FOR1(a) for (ll _ = 0; _ < ll(a); ++_)
#define FOR2(i, a) for (ll i = 0; i < ll(a); ++i)
#define FOR3(i, a, b) for (ll i = a; i < ll(b); ++i)
#define FOR1_R(a) for (ll i = ll(a) - 1; i >= ll(0); --i)
#define FOR2_R(i, a) for (ll i = ll(a) - 1; i >= ll(0); --i)
#define FOR3_R(i, a, b) for (ll i = ll(b) - 1; i >= ll(a); --i)
#define overload3(a, b, c, d, ...) d
#define FOR(...) overload3(__VA_ARGS__, FOR3, FOR2, FOR1)(__VA_ARGS__)
#define FOR_R(...) overload3(__VA_ARGS__, FOR3_R, FOR2_R, FOR1_R)(__VA_ARGS__)

#define all(x) (x).begin(), (x).end()
#define len(x) ll(x.size())
#define elif else if

#define eb emplace_back
#define mp make_pair
#define mt make_tuple
#define fi first
#define se second

#define stoi stoll

// require y > 0
template <typename T>
T floor(T x, T y) {
  return x / y - (x % y < 0);
}

// require y > 0
template <typename T>
T ceil(T x, T y) {
  return (x / y) + (x % y > 0);
}

// require y > 0
template <typename T>
T bmod(T x, T y) {
  T r = x % y;
  return (r < 0 ? r + y : r);
}

// require y > 0
template <typename T>
pair<T, T> divmod(T x, T y) {
  T q = x / y, r = x % y;
  if (r < 0) --q, r += y;
  return {q, r};
}

constexpr auto TEN = [] {
  array<u64, 20> A{};
  A[0] = 1;
  for (int i = 1; i < 20; ++i) A[i] = 10 * A[i - 1];
  return A;
}();

template <typename T, typename U>
T SUM(const U &A) {
  return std::accumulate(A.begin(), A.end(), T{});
}

#define MIN(v) *min_element(all(v))
#define MAX(v) *max_element(all(v))
template <class C, class T>
inline long long LB(const C &c, const T &x) {
  return lower_bound(c.begin(), c.end(), x) - c.begin();
}
template <class C, class T>
inline long long UB(const C &c, const T &x) {
  return upper_bound(c.begin(), c.end(), x) - c.begin();
}
#define UNIQUE(x) sort(all(x)), x.erase(unique(all(x)), x.end())

template <typename T>
T POP(deque<T> &que) {
  T a = que.front();
  que.pop_front();
  return a;
}
template <class T, class Container, class Compare>
T POP(priority_queue<T, Container, Compare> &que) {
  T a = que.top();
  que.pop();
  return a;
}
template <typename T>
T POP(vc<T> &que) {
  T a = que.back();
  que.pop_back();
  return a;
}

template <typename F>
i128 binary_search(F check, i128 ok, i128 ng, bool check_ok = true) {
  if (check_ok) assert(check(ok));
  while (1) {
    i128 x = (ok + ng) / 2;
    if (x == ok || x == ng) break;
    (check(x) ? ok : ng) = x;
  }
  return ok;
}

template <typename F>
double binary_search_real(F check, double ok, double ng, int iter = 100) {
  FOR(iter) {
    double x = (ok + ng) / 2;
    (check(x) ? ok : ng) = x;
  }
  return (ok + ng) / 2;
}

template <class T, class S>
inline bool chmax(T &a, const S &b) {
  T c = max<T>(a, b);
  bool changed = (c != a);
  a = c;
  return changed;
}
template <class T, class S>
inline bool chmin(T &a, const S &b) {
  T c = min<T>(a, b);
  bool changed = (c != a);
  a = c;
  return changed;
}

// bit operations
int popcnt(int x) { return __builtin_popcount(x); }
int popcnt(u32 x) { return __builtin_popcount(x); }
int popcnt(ll x) { return __builtin_popcountll(x); }
int popcnt(u64 x) { return __builtin_popcountll(x); }
int popcnt_sgn(int x) { return (__builtin_parity(unsigned(x)) & 1 ? -1 : 1); }
int popcnt_sgn(u32 x) { return (__builtin_parity(x) & 1 ? -1 : 1); }
int popcnt_sgn(ll x) { return (__builtin_parityll(x) & 1 ? -1 : 1); }
int popcnt_sgn(u64 x) { return (__builtin_parityll(x) & 1 ? -1 : 1); }
// (0, 1, 2, 3, 4) -> (-1, 0, 1, 1, 2)
int topbit(int x) { return (x == 0 ? -1 : 31 - __builtin_clz(x)); }
int topbit(u32 x) { return (x == 0 ? -1 : 31 - __builtin_clz(x)); }
int topbit(ll x) { return (x == 0 ? -1 : 63 - __builtin_clzll(x)); }
int topbit(u64 x) { return (x == 0 ? -1 : 63 - __builtin_clzll(x)); }
// (0, 1, 2, 3, 4) -> (-1, 0, 1, 0, 2)
int lowbit(int x) { return (x == 0 ? -1 : __builtin_ctz(x)); }
int lowbit(u32 x) { return (x == 0 ? -1 : __builtin_ctz(x)); }
int lowbit(ll x) { return (x == 0 ? -1 : __builtin_ctzll(x)); }
int lowbit(u64 x) { return (x == 0 ? -1 : __builtin_ctzll(x)); }

template <typename T>
T kth_bit(int k) {
  assert(0 <= k && k < int(8 * sizeof(T)));
  return T(1) << k;
}
template <typename T>
bool has_kth_bit(T x, int k) {
  assert(0 <= k && k < int(8 * sizeof(T)));
  return x >> k & 1;
}

template <typename T>
struct all_bit {
  static_assert(is_integral<T>::value);
  T s;
  all_bit(T s) : s(s) { assert(s >= 0); }
  struct iter {
    T s;
    int operator*() const { return lowbit(s); }
    void operator++() { s &= s - 1; }
    bool operator!=(nullptr_t) const { return s; }
  };
  iter begin() const { return {s}; }
  nullptr_t end() const { return nullptr; }
};

template <typename T>
struct all_subset {
  static_assert(is_integral<T>::value);
  T s;
  all_subset(T s) : s(s) { assert(s >= 0); }
  struct iter {
    T s, t;
    bool done = false;
    T operator*() const { return t; }
    void operator++() {
      done = (t == 0);
      t = (t - 1) & s;
    }
    bool operator!=(nullptr_t) const { return !done; }
  };
  iter begin() const { return {s, s}; }
  nullptr_t end() const { return nullptr; }
};

constexpr u64 full_mask(int n) {
  assert(0 <= n && n <= 64);
  return n == 64 ? -1ULL : (1ULL << n) - 1;
}

u64 bit_reverse(u64 x) {
  x = ((x & 0x5555555555555555ULL) << 1) | ((x >> 1) & 0x5555555555555555ULL);
  x = ((x & 0x3333333333333333ULL) << 2) | ((x >> 2) & 0x3333333333333333ULL);
  x = ((x & 0x0f0f0f0f0f0f0f0fULL) << 4) | ((x >> 4) & 0x0f0f0f0f0f0f0f0fULL);
  x = ((x & 0x00ff00ff00ff00ffULL) << 8) | ((x >> 8) & 0x00ff00ff00ff00ffULL);
  x = ((x & 0x0000ffff0000ffffULL) << 16) | ((x >> 16) & 0x0000ffff0000ffffULL);
  x = (x << 32) | (x >> 32);
  return x;
}

// ? は -1
vc<int> s_to_vi(const string &S, char first_char) {
  vc<int> A(S.size());
  FOR(i, S.size()) { A[i] = (S[i] != '?' ? S[i] - first_char : -1); }
  return A;
}

template <typename T, typename U>
vc<T> cumsum(const vc<U> &A, int off = 1) {
  int N = A.size();
  vc<T> B(N + 1);
  FOR(i, N) { B[i + 1] = B[i] + A[i]; }
  if (off == 0) B.erase(B.begin());
  return B;
}

// stable sort
template <typename T>
vc<int> argsort(const vc<T> &A) {
  vc<int> ids(len(A));
  iota(all(ids), 0);
  sort(all(ids),
      [&](int i, int j) { return (A[i] == A[j] ? i < j : A[i] < A[j]); });
  return ids;
}

// A[I[0]], A[I[1]], ...
template <typename T>
vc<T> rearrange(const vc<T> &A, const vc<int> &I) {
  vc<T> B(len(I));
  FOR(i, len(I)) B[i] = A[I[i]];
  return B;
}

template <typename T, typename... Vectors>
void concat(vc<T> &first, const Vectors &...others) {
  first.reserve(first.size() + (others.size() + ... + 0));
  (first.insert(first.end(), others.begin(), others.end()), ...);
}

// i128
template <class T, enable_if_t<is_same_v<T, i128>, int> = 0>
constexpr i128 abs(T x) {
  return x < 0 ? -x : x;
}

constexpr i128 gcd(i128 a, i128 b) {
  while (b != 0) {
    i128 c = a % b;
    a = b, b = c;
  }
  return abs(a);
}
#endif  // MASPY_TEMPLATE_BODY
#line 1 "other/io.hpp"
// Source: https://github.com/maspypy/library/blob/main/other/io.hpp
#define FASTIO

// https://judge.yosupo.jp/submission/21623
namespace fastio {
static constexpr uint32_t SZ = 1 << 17;
char ibuf[SZ];
char obuf[SZ];
char out[100];
// pointer of ibuf, obuf
uint32_t pil = 0, pir = 0, por = 0;
bool input_eof = false;

template <class T>
constexpr bool is_signed_integer_v = is_signed_v<T> || is_same_v<T, i128>;

template <class T>
struct unsigned_integer {
  using type = make_unsigned_t<T>;
};
template <>
struct unsigned_integer<i128> {
  using type = u128;
};
template <>
struct unsigned_integer<u128> {
  using type = u128;
};
template <class T>
using unsigned_integer_t = typename unsigned_integer<T>::type;

[[noreturn]] inline void input_error(const char *message) {
  fputs(message, stderr);
  fputc('\n', stderr);
  exit(EXIT_FAILURE);
}

struct Pre {
  char num[10000][4];
  constexpr Pre() : num() {
    for (int i = 0; i < 10000; i++) {
      int n = i;
      for (int j = 3; j >= 0; j--) {
        num[i][j] = n % 10 | '0';
        n /= 10;
      }
    }
  }
} constexpr pre;

inline void load() {
  uint32_t n = pir - pil;
  memmove(ibuf, ibuf + pil, n);
  pil = 0;
  pir = n;
  if (input_eof) return;

  pir += fread(ibuf + pir, 1, SZ - pir, stdin);
  if (ferror(stdin)) input_error("fastio: input error");
  if (feof(stdin)) {
    input_eof = true;
    // Allows the last token to end exactly at EOF without a trailing
    // whitespace.
    if (pir < SZ) ibuf[pir++] = '\n';
  }
}

inline char get_char() {
  if (pil == pir) {
    load();
    if (pil == pir) input_error("fastio: unexpected EOF");
  }
  return ibuf[pil++];
}

inline void flush() {
  fwrite(obuf, 1, por, stdout);
  por = 0;
}

void rd(char &c) {
  do c = get_char();
  while (isspace(static_cast<unsigned char>(c)));
}

void rd(string &x) {
  x.clear();
  char c;
  do c = get_char();
  while (isspace(static_cast<unsigned char>(c)));
  do {
    x += c;
    c = get_char();
  } while (!isspace(static_cast<unsigned char>(c)));
}

template <typename T>
void rd_real(T &x) {
  string s;
  rd(s);
  x = stod(s);
}

template <typename T>
void rd_integer_slow(T &x) {
  char c;
  do c = get_char();
  while (c < '-');
  bool minus = 0;
  if constexpr (is_signed_integer_v<T>) {
    if (c == '-') {
      minus = 1, c = get_char();
    }
  }
  x = 0;
  assert('0' <= c && c <= '9');
  while ('0' <= c && c <= '9') {
    x = x * 10 + (c & 15), c = get_char();
  }
  assert(isspace(static_cast<unsigned char>(c)));
  if constexpr (is_signed_integer_v<T>) {
    if (minus) x = -x;
  }
}

template <typename T>
void rd_integer(T &x) {
  if (pil + 100 > pir) {
    load();
    if (pil + 100 > pir) {
      rd_integer_slow(x);
      return;
    }
  }
  char c;
  do c = ibuf[pil++];
  while (c < '-');
  bool minus = 0;
  if constexpr (is_signed_integer_v<T>) {
    if (c == '-') {
      minus = 1, c = ibuf[pil++];
    }
  }
  x = 0;
  assert('0' <= c && c <= '9');
  while ('0' <= c && c <= '9') {
    x = x * 10 + (c & 15), c = ibuf[pil++];
  }
  assert(isspace(static_cast<unsigned char>(c)));
  if constexpr (is_signed_integer_v<T>) {
    if (minus) x = -x;
  }
}

template <class T>
enable_if_t<is_integral_v<T> || is_same_v<T, i128> || is_same_v<T, u128>> rd(
    T &x) {
  rd_integer(x);
}

template <class T>
enable_if_t<is_floating_point_v<T> || is_same_v<T, f128>> rd(T &x) {
  rd_real(x);
}

template <class T, class U>
void rd(pair<T, U> &p) {
  rd(p.first), rd(p.second);
}
template <size_t N = 0, typename T>
void rd_tuple(T &t) {
  if constexpr (N < tuple_size<T>::value) {
    auto &x = get<N>(t);
    rd(x);
    rd_tuple<N + 1>(t);
  }
}
template <class... T>
void rd(tuple<T...> &tpl) {
  rd_tuple(tpl);
}

template <class T, size_t N>
void rd(array<T, N> &x) {
  for (auto &d : x) rd(d);
}
template <class T>
void rd(vc<T> &x) {
  for (auto &d : x) rd(d);
}

template <class... T>
void read(T &...x) {
  (rd(x), ...);
}

inline void wt_range(const char *s, size_t n) {
  size_t i = 0;
  while (i < n) {
    if (por == SZ) flush();
    size_t chunk = min(n - i, (size_t)(SZ - por));
    memcpy(obuf + por, s + i, chunk);
    por += chunk;
    i += chunk;
  }
}

void wt(const char c) {
  if (por == SZ) flush();
  obuf[por++] = c;
}
void wt(const char *s) { wt_range(s, strlen(s)); }
void wt(const string &s) { wt_range(s.data(), s.size()); }

template <typename T>
void wt_integer(T x) {
  if (por > SZ - 100) flush();
  using U = unsigned_integer_t<T>;
  U y = static_cast<U>(x);
  if constexpr (is_signed_integer_v<T>) {
    if (x < 0) {
      obuf[por++] = '-';
      y = U(0) - y;
    }
  }
  int outi;
  for (outi = 96; y >= 10000; outi -= 4) {
    memcpy(out + outi, pre.num[y % 10000], 4);
    y /= 10000;
  }
  if (y >= 1000) {
    memcpy(obuf + por, pre.num[y], 4);
    por += 4;
  } else if (y >= 100) {
    memcpy(obuf + por, pre.num[y] + 1, 3);
    por += 3;
  } else if (y >= 10) {
    int q = (y * 103) >> 10;
    obuf[por] = q | '0';
    obuf[por + 1] = (y - q * 10) | '0';
    por += 2;
  } else
    obuf[por++] = y | '0';
  memcpy(obuf + por, out + outi + 4, 96 - outi);
  por += 96 - outi;
}

template <typename T>
inline void wt_real(T x) {
  static char buf[1000];
  int n = std::snprintf(buf, sizeof(buf), "%.15f", (double)x);
  wt_range(buf, (size_t)n);
}

template <class T>
enable_if_t<is_integral_v<T> || is_same_v<T, i128> || is_same_v<T, u128>> wt(
    T x) {
  wt_integer(x);
}

template <class T>
enable_if_t<is_floating_point_v<T> || is_same_v<T, f128>> wt(T x) {
  wt_real(x);
}

inline void wt(bool b) { wt(static_cast<char>('0' + (b ? 1 : 0))); }

template <class T, class U>
void wt(const pair<T, U> &val) {
  wt(val.first);
  wt(' ');
  wt(val.second);
}
template <size_t N = 0, typename T>
void wt_tuple(const T &t) {
  if constexpr (N < tuple_size<T>::value) {
    if constexpr (N > 0) wt(' ');
    wt(get<N>(t));
    wt_tuple<N + 1>(t);
  }
}
template <class... T>
void wt(const tuple<T...> &tpl) {
  wt_tuple(tpl);
}
template <class T, size_t S>
void wt(const array<T, S> &val) {
  auto n = val.size();
  for (size_t i = 0; i < n; i++) {
    if (i) wt(' ');
    wt(val[i]);
  }
}
template <class T>
void wt(const vector<T> &val) {
  auto n = val.size();
  for (size_t i = 0; i < n; i++) {
    if (i) wt(' ');
    wt(val[i]);
  }
}

void print() { wt('\n'); }
template <class Head, class... Tail>
void print(Head &&head, Tail &&...tail) {
  wt(forward<Head>(head));
  ((wt(' '), wt(forward<Tail>(tail))), ...);
  wt('\n');
}

// gcc expansion. called automaticall after main.
void __attribute__((destructor)) _d() { flush(); }
}  // namespace fastio
using fastio::flush;
using fastio::print;
using fastio::read;

#if defined(LOCAL)
#define HDR "[DEBUG:", __func__, __LINE__, "]"
#define SHOW(...)                                                         \
  SHOW_IMPL(__VA_ARGS__, SHOW8, SHOW7, SHOW6, SHOW5, SHOW4, SHOW3, SHOW2, \
            SHOW1)                                                        \
  (__VA_ARGS__)
#define SHOW_IMPL(_1, _2, _3, _4, _5, _6, _7, _8, NAME, ...) NAME
#define SHOW1(x) print(HDR, #x, "=", (x)), flush()
#define SHOW2(x, y) print(HDR, #x, "=", (x), #y, "=", (y)), flush()
#define SHOW3(x, y, z) \
  print(HDR, #x, "=", (x), #y, "=", (y), #z, "=", (z)), flush()
#define SHOW4(x, y, z, w) \
  print(HDR, #x, "=", (x), #y, "=", (y), #z, "=", (z), #w, "=", (w)), flush()
#define SHOW5(x, y, z, w, v)                                                  \
  print(HDR, #x, "=", (x), #y, "=", (y), #z, "=", (z), #w, "=", (w), #v, "=", \
        (v)),                                                                 \
      flush()
#define SHOW6(x, y, z, w, v, u)                                               \
  print(HDR, #x, "=", (x), #y, "=", (y), #z, "=", (z), #w, "=", (w), #v, "=", \
        (v), #u, "=", (u)),                                                   \
      flush()
#define SHOW7(x, y, z, w, v, u, t)                                            \
  print(HDR, #x, "=", (x), #y, "=", (y), #z, "=", (z), #w, "=", (w), #v, "=", \
        (v), #u, "=", (u), #t, "=", (t)),                                     \
      flush()
#define SHOW8(x, y, z, w, v, u, t, s)                                         \
  print(HDR, #x, "=", (x), #y, "=", (y), #z, "=", (z), #w, "=", (w), #v, "=", \
        (v), #u, "=", (u), #t, "=", (t), #s, "=", (s)),                       \
      flush()
#else
#define SHOW(...)
#endif

#define INT(...)   \
  int __VA_ARGS__; \
  read(__VA_ARGS__)
#define LL(...)   \
  ll __VA_ARGS__; \
  read(__VA_ARGS__)
#define U32(...)   \
  u32 __VA_ARGS__; \
  read(__VA_ARGS__)
#define U64(...)   \
  u64 __VA_ARGS__; \
  read(__VA_ARGS__)
#define STR(...)      \
  string __VA_ARGS__; \
  read(__VA_ARGS__)
#define CHAR(...)   \
  char __VA_ARGS__; \
  read(__VA_ARGS__)
#define DBL(...)      \
  double __VA_ARGS__; \
  read(__VA_ARGS__)

#define VEC(type, name, size) \
  vector<type> name(size);    \
  read(name)
#define VV(type, name, h, w)                     \
  vector<vector<type>> name(h, vector<type>(w)); \
  read(name)

void YES(bool t = 1) { print(t ? "YES" : "NO"); }
void NO(bool t = 1) { YES(!t); }
void Yes(bool t = 1) { print(t ? "Yes" : "No"); }
void No(bool t = 1) { Yes(!t); }
void yes(bool t = 1) { print(t ? "yes" : "no"); }
void no(bool t = 1) { yes(!t); }
void YA(bool t = 1) { print(t ? "YA" : "TIDAK"); }
void TIDAK(bool t = 1) { YA(!t); }
void Alice(bool t = 1) { print(t ? "Alice" : "Bob"); }
void Bob(bool t = 1) { Alice(!t); }
#line 4 "test/3_yukicoder/2809.test.cpp"

#line 1 "ds/sortable_array.hpp"
// Source: https://github.com/maspypy/library/blob/main/ds/sortable_array.hpp
#line 1 "ds/fastset.hpp"
// Source: https://github.com/maspypy/library/blob/main/ds/fastset.hpp
// 64-ary tree
// space: (N/63) * u64
struct FastSet {
  static constexpr u32 B = 64;
  int n = 0, log = 0;
  vvc<u64> seg;

  FastSet() {}
  FastSet(int n) { build(n); }

  int size() { return n; }

  void fill_one() {
    int cur = n;
    for (auto& vs : seg) {
      int p = cur / B, q = cur % B;
      FOR(i, p) vs[i] = -1ull;
      if (q) vs[p] = full_mask(q);
      cur = (cur + B - 1) / B;
    }
  }

  template <typename F>
  FastSet(int n, F f) {
    build(n, f);
  }

  void build(int m) {
    seg.clear();
    n = m;
    do {
      seg.push_back(vc<u64>((m + B - 1) / B));
      m = (m + B - 1) / B;
    } while (m > 1);
    log = len(seg);
  }
  template <typename F>
  void build(int n, F f) {
    build(n);
    FOR(i, n) { seg[0][i / B] |= u64(bool(f(i))) << (i % B); }
    FOR(h, log - 1) {
      FOR(i, len(seg[h])) {
        seg[h + 1][i / B] |= u64(bool(seg[h][i])) << (i % B);
      }
    }
  }

  bool operator[](int i) const {
    assert(0 <= i && i < n);
    return seg[0][i / B] >> (i % B) & 1;
  }
  void insert(int i) {
    assert(0 <= i && i < n);
    for (int h = 0; h < log; h++) {
      u64& x = seg[h][i / B];
      u64 mask = u64(1) << (i % B);
      if (x & mask) return;
      x |= mask;
      i /= B;
    }
  }
  void add(int i) { insert(i); }
  void erase(int i) {
    assert(0 <= i && i < n);
    for (int h = 0; h < log; h++) {
      u64& x = seg[h][i / B];
      u64 mask = u64(1) << (i % B);
      if (!(x & mask)) return;
      x ^= mask;
      if (x) return;
      i /= B;
    }
  }
  void remove(int i) { erase(i); }

  // min[x,n) or n
  int next(int i) {
    assert(i <= n);
    chmax(i, 0);
    for (int h = 0; h < log; h++) {
      if (i / B == seg[h].size()) break;
      u64 d = seg[h][i / B] >> (i % B);
      if (!d) {
        i = i / B + 1;
        continue;
      }
      i += lowbit(d);
      for (int g = h - 1; g >= 0; g--) {
        i *= B;
        i += lowbit(seg[g][i / B]);
      }
      return i;
    }
    return n;
  }

  // max [0,x], or -1
  int prev(int i) {
    assert(i >= -1);
    if (i >= n) i = n - 1;
    for (int h = 0; h < log; h++) {
      if (i == -1) break;
      u64 d = seg[h][i / B] << (63 - i % B);
      if (!d) {
        i = i / B - 1;
        continue;
      }
      i -= __builtin_clzll(d);
      for (int g = h - 1; g >= 0; g--) {
        i *= B;
        i += topbit(seg[g][i / B]);
      }
      return i;
    }
    return -1;
  }

  bool any(int l, int r) {
    assert(0 <= l && l <= r && r <= n);
    return next(l) < r;
  }

  // [l, r). erase=true のとき、callback 内から this を変更してはいけない。
  template <typename F>
  void enumerate(int l, int r, F f, bool erase = false) {
    assert(0 <= l && l <= r && r <= n);
    if (!erase) {
      for (int x = next(l); x < r; x = next(x + 1)) f(x);
      return;
    }
    for (int x = next(l); x < r;) {
      int w = x / B;
      int lo = max(l, w * int(B)) - w * int(B);
      int hi = min(r, (w + 1) * int(B)) - w * int(B);
      u64 erase_bits = seg[0][w] & (full_mask(hi) & ~full_mask(lo));
      u64 bits = erase_bits;
      while (bits) {
        int k = lowbit(bits);
        f(w * int(B) + k);
        bits ^= u64(1) << k;
      }
      seg[0][w] ^= erase_bits;
      if (!seg[0][w]) propagate_empty_word(w);
      x = next(min(r, (w + 1) * int(B)));
    }
  }

  void reset() {
    int x = next(0);
    while (x < n) {
      int w = x / B;
      seg[0][w] = 0;
      propagate_empty_word(w);
      x = next(min(n, (w + 1) * int(B)));
    }
  }

  string to_string() {
    string s(n, '?');
    for (int i = 0; i < n; ++i) s[i] = ((*this)[i] ? '1' : '0');
    return s;
  }

 private:
  // seg[0][w] が 0 になった後に呼ぶ。
  void propagate_empty_word(int i) {
    for (int h = 1; h < log; ++h) {
      u64& y = seg[h][i / B];
      u64 mask = u64(1) << (i % B);
      y ^= mask;
      if (y) break;
      i /= B;
    }
  }
};
#line 1 "ds/node_pool.hpp"
// Source: https://github.com/maspypy/library/blob/main/ds/node_pool.hpp
// マルチテストケースでも確保済み chunk を再利用する
template <class Node>
struct Node_Pool {
  union Slot {
    Node node;
    Slot* next;

    Slot() {}
    ~Slot() {}
  };
  using np = Node*;

  static constexpr int CHUNK_SIZE = 1 << 12;

  vc<unique_ptr<Slot[]>> chunks;
  int chunk_id = 0;
  int pos = 0;
  Slot* free_head = nullptr;

  ~Node_Pool() {
    auto& cache = chunk_cache();
    for (auto& p : chunks) cache.eb(std::move(p));
  }

  template <class... Args>
  np create(Args&&... args) {
    Slot* s = new_slot();
    return ::new (&s->node) Node(forward<Args>(args)...);
  }

  np clone(const np x) {
    assert(x);
    Slot* s = new_slot();
    return ::new (&s->node) Node(*x);
  }

  void destroy(np x) {
    if (!x) return;
    x->~Node();
    Slot* s = reinterpret_cast<Slot*>(x);
    s->next = free_head;
    free_head = s;
  }

  // 全 node を無効化する。
  // 確保済み chunk は解放せず、次回以降に再利用する。
  void reset() {
    free_head = nullptr;
    chunk_id = 0;
    pos = 0;
  }

  int used() const { return chunk_id * CHUNK_SIZE + pos; }

 private:
  static vc<unique_ptr<Slot[]>>& chunk_cache() {
    // static Node_Pool の destructor より先に破棄されないようにする。
    static auto* cache = new vc<unique_ptr<Slot[]>>();
    return *cache;
  }

  void alloc_chunk() {
    auto& cache = chunk_cache();
    if (cache.empty()) {
      chunks.eb(make_unique<Slot[]>(CHUNK_SIZE));
    } else {
      chunks.eb(std::move(cache.back()));
      cache.pop_back();
    }
  }

  Slot* new_slot() {
    if (free_head) {
      Slot* s = free_head;
      free_head = free_head->next;
      return s;
    }

    if (chunk_id == len(chunks)) alloc_chunk();

    Slot* s = &chunks[chunk_id][pos++];
    if (pos == CHUNK_SIZE) {
      ++chunk_id;
      pos = 0;
    }
    return s;
  }
};
#line 4 "ds/sortable_array.hpp"

// int 列を扱う. key の重複可.
struct Sortable_Array {
  const int N, KEY_MAX;

  struct Node {
    int size;
    Node *l, *r;
  };
  Node_Pool<Node> pool;
  using np = Node*;

  FastSet ss;       // 区間の左端全体を表す fastset
  vector<np> root;  // 区間の左端に、dynamic segtree の node を乗せる
  vector<bool> rev;

  Sortable_Array(int NODES, int KEY_MAX, vector<int> key)
      : N(key.size()), KEY_MAX(KEY_MAX), ss(key.size()) {
    init(key);
  }

  void set(int i, int key) {
    assert(0 <= key && key < KEY_MAX);
    split_at(i), split_at(i + 1);
    rev[i] = 0, root[i] = new_node(0);
    set_rec(root[i], 0, KEY_MAX, key);
  }

  void sort_inc(int l, int r) {
    if (l == r) return;
    split_at(l), split_at(r);
    while (1) {
      np c = root[l];
      int i = ss.next(l + 1);
      if (i == r) break;
      root[l] = merge(0, KEY_MAX, c, root[i]);
      ss.erase(i);
    }
    rev[l] = 0;
  };

  void sort_dec(int l, int r) {
    if (l == r) return;
    sort_inc(l, r), rev[l] = 1;
  };

  vc<int> get_all() {
    vector<int> key;
    key.reserve(N);
    auto dfs = [&](auto& dfs, np n, int l, int r, bool rev) -> void {
      if (!n || !n->size) return;
      if (r == l + 1) {
        FOR(n->size) key.eb(l);
        return;
      }
      int m = (l + r) / 2;
      if (!rev) {
        dfs(dfs, n->l, l, m, rev), dfs(dfs, n->r, m, r, rev);
      }
      if (rev) {
        dfs(dfs, n->r, m, r, rev), dfs(dfs, n->l, l, m, rev);
      }
    };
    for (int i = 0; i < N; ++i) {
      if (ss[i]) dfs(dfs, root[i], 0, KEY_MAX, rev[i]);
    }
    return key;
  }

  int get(int idx) {
    auto dfs = [&](auto& dfs, np n, int l, int r, int k) -> int {
      if (r == l + 1) {
        return l;
      }
      int m = (l + r) / 2;
      int s = (n->l ? n->l->size : 0);
      if (k < s) return dfs(dfs, n->l, l, m, k);
      return dfs(dfs, n->r, m, r, k - s);
    };
    int i = ss.prev(idx);
    int k = idx - i;
    int s = root[i]->size;
    if (rev[i]) k = s - 1 - k;
    return dfs(dfs, root[i], 0, KEY_MAX, k);
  }

 private:
  void init(vector<int>& key) {
    rev.assign(N, 0), root.clear(), root.reserve(N);
    ss.build(N, [&](int i) -> int { return 1; });
    for (int i = 0; i < N; ++i) {
      root.eb(new_node(0));
      assert(key[i] < KEY_MAX);
      set_rec(root[i], 0, KEY_MAX, key[i]);
    }
  }

  // x が左端になるようにする
  void split_at(int x) {
    if (x == N || ss[x]) return;
    int a = ss.prev(x), b = ss.next(a + 1);
    ss.insert(x);
    if (!rev[a]) {
      auto [nl, nr] = split(root[a], 0, KEY_MAX, x - a);
      root[a] = nl, root[x] = nr;
      rev[a] = rev[x] = 0;
    } else {
      auto [nl, nr] = split(root[a], 0, KEY_MAX, b - x);
      root[a] = nr, root[x] = nl;
      rev[a] = rev[x] = 1;
    }
  }

  void rebuild() {
    auto key = get_all();
    pool.reset();
    init(key);
  }

  np new_node(int size) {
    np c = pool.create();
    c->l = c->r = nullptr, c->size = size;
    return c;
  }

  pair<np, np> split(np n, int l, int r, int k) {
    if (k == 0) {
      return {nullptr, n};
    }
    if (k == n->size) {
      return {n, nullptr};
    }
    if (r == l + 1) {
      int s = n->size;
      n->size = k;
      Node* b = new_node(s - k);
      return {n, b};
    }
    int s = (n->l ? n->l->size : 0);
    Node* b = new_node(0);
    int m = (l + r) / 2;
    if (k <= s) {
      auto [nl, nr] = split(n->l, l, m, k);
      b->l = nr, b->r = n->r, n->l = nl, n->r = nullptr;
    }
    if (k > s) {
      auto [nl, nr] = split(n->r, m, r, k - s);
      n->l = n->l, n->r = nl, b->l = nullptr, b->r = nr;
    }
    update(n), update(b);
    return {n, b};
  }

  np merge(int l, int r, np a, np b) {
    if (!a) return b;
    if (!b) return a;
    if (r == l + 1) {
      a->size += b->size;
      return a;
    }
    int m = (l + r) / 2;
    a->l = merge(l, m, a->l, b->l), a->r = merge(m, r, a->r, b->r);
    update(a);
    return a;
  }

  void update(np n) {
    if (!(n->l) && !(n->r)) {
      return;
    }
    if (!(n->l)) {
      n->size = n->r->size;
      return;
    }
    if (!(n->r)) {
      n->size = n->l->size;
      return;
    }
    n->size = n->l->size + n->r->size;
  }

  void set_rec(np n, int l, int r, int k) {
    if (r == l + 1) {
      n->size = 1;
      return;
    }
    int m = (l + r) / 2;
    if (k < m) {
      if (!(n->l)) n->l = new_node(0);
      set_rec(n->l, l, m, k);
    }
    if (m <= k) {
      if (!(n->r)) n->r = new_node(0);
      set_rec(n->r, m, r, k);
    }
    update(n);
  }
};
#line 6 "test/3_yukicoder/2809.test.cpp"

void solve() {
  LL(N, Q);
  VEC(ll, A, N);
  vc<tuple<ll, ll, ll>> query;
  vi X = A;
  FOR(Q) {
    INT(t);
    if (t == 1) {
      LL(k, x);
      query.eb(t, --k, x);
      X.eb(x);
    }
    if (t == 2) { query.eb(t, -1, -1); }
    if (t == 3) {
      LL(k);
      query.eb(t, --k, -1);
    }
  }
  UNIQUE(X);
  for (auto& x: A) x = LB(X, x);

  vc<int> now(N);
  FOR(i, N) now[i] = A[i];
  Sortable_Array SA(20000000, len(X), now);

  for (auto& [t, k, x]: query) {
    if (t == 1) {
      x = LB(X, x);
      SA.set(k, x);
    }
    if (t == 2) { SA.sort_inc(0, N); }
    if (t == 3) {
      ll x = SA.get(k);
      print(X[x]);
    }
  }
}

signed main() {
  int T = 1;
  // INT(T);
  FOR(T) solve();
  return 0;
}
Back to top page