「BZOJ3065」带插入区间K小值 [分块]

考虑分块,每个块都是用 链表 维护的,并保证 (size) 和分块相当。

我们考虑一下怎么去查询,很显然,可以对值域分块,单点修改,记录前缀和,完全ojbk了,对每个块维护一个 (pre , prb) 数组

(pre_{i,j}) 数组表示 (1~i) 这些块中,出现了多少个 (j)
(prb_{i,j}) 数组表示 (1~i) 这些块中,在值域块 (j) 的有多少个
零散部分查一查就好了,修改也是稳定 (sqrt n) 的,插入也是。

// powered by c++11
// by Isaunoya
#pragma GCC optimize("Ofast")
#pragma GCC optimize("unroll-loops")
#pragma GCC target("sse,sse2,sse3,ssse3,sse4,popcnt,abm,mmx,avx,tune=native")
#include <bits/stdc++.h>
#define rep(i, x, y) for (register int i = (x); i <= (y); ++i)
#define Rep(i, x, y) for (register int i = (x); i >= (y); --i)
using namespace std;
using db = double;
using ll = long long;
using uint = unsigned int;
using pii = pair<int, int>;
#define ve vector
#define Tp template
#define all(v) v.begin(), v.end()
#define sz(v) ((int)v.size())
#define pb emplace_back
#define fir first
#define sec second
// the cmin && cmax
Tp<class T> void cmax(T& x, const T& y) {
  if (x < y) x = y;
}
Tp<class T> void cmin(T& x, const T& y) {
  if (x > y) x = y;
}
// sort , unique , reverse
Tp<class T> void sort(ve<T>& v) { sort(all(v)); }
Tp<class T> void unique(ve<T>& v) {
  sort(all(v));
  v.erase(unique(all(v)), v.end());
}
Tp<class T> void reverse(ve<T>& v) { reverse(all(v)); }
const int SZ = 0x191981;
struct FILEIN {
  char qwq[SZ], *S = qwq, *T = qwq, ch;
  char GETC() { return (S == T) && (T = (S = qwq) + fread(qwq, 1, SZ, stdin), S == T) ? EOF : *S++; }
  FILEIN& operator>>(char& c) {
    while (isspace(c = GETC()))
      ;
    return *this;
  }
  FILEIN& operator>>(string& s) {
    while (isspace(ch = GETC()))
      ;
    s = ch;
    while (!isspace(ch = GETC())) s += ch;
    return *this;
  }
  Tp<class T> void read(T& x) {
    bool sign = 1;
    while ((ch = GETC()) < 0x30)
      if (ch == 0x2d) sign = 0;
    x = (ch ^ 0x30);
    while ((ch = GETC()) > 0x2f) x = x * 0xa + (ch ^ 0x30);
    x = sign ? x : -x;
  }
  FILEIN& operator>>(int& x) { return read(x), *this; }
  FILEIN& operator>>(unsigned& x) { return read(x), *this; }
} in;
struct FILEOUT {
  const static int LIMIT = 0x114514;
  char quq[SZ], ST[0x114];
  signed sz, O;
  ~FILEOUT() { flush(); }
  void flush() {
    fwrite(quq, 1, O, stdout);
    fflush(stdout);
    O = 0;
  }
  FILEOUT& operator<<(char c) { return quq[O++] = c, *this; }
  FILEOUT& operator<<(string str) {
    if (O > LIMIT) flush();
    for (char c : str) quq[O++] = c;
    return *this;
  }
  Tp<class T> void write(T x) {
    if (O > LIMIT) flush();
    if (x < 0) {
      quq[O++] = 0x2d;
      x = -x;
    }
    do {
      ST[++sz] = x % 0xa ^ 0x30;
      x /= 0xa;
    } while (x);
    while (sz) quq[O++] = ST[sz--];
    return;
  }
  FILEOUT& operator<<(int x) { return write(x), *this; }
  FILEOUT& operator<<(unsigned x) { return write(x), *this; }
} out;
int n, m;
const int maxn = 7e4 + 47;
const int blc = 235;
const int S = 300;
list<int> s[S];
#define bl(x) ((x - 1) / S + 1)
int pre[maxn][S], prb[S][S], L[S], R[S], cnt[maxn], t[S], st[S << 1], top = 0, ans = 0;
inline int modify(list<int>& l, int x, int v) {
  auto it = l.begin();
  while (x--) ++it;
  int res = *(it);
  return *(it) = v, res;
}
inline void get(list<int>& l, int x, int y) {
  auto it = l.begin();
  while (x--) ++it;
  while (y--) {
    ++cnt[st[++top] = *(it)], ++t[bl(*(it))], ++it;
  }
}
void qry(int l, int r, int k) {
  top = 0;
  const int bL = bl(l), bR = bl(r);
  if (bL == bR) {
    get(s[bL], l - L[bL], r - l + 1);
    for (int i = 1;; i++) {
      if (k > t[i]) {
        k -= t[i];
      } else {
        for (int j = L[i];; ++j)
          if (k > cnt[j]) {
            k -= cnt[j];
          } else {
            ans = j;
            break;
          }
        break;
      }
    }
  } else {
    get(s[bL], l - L[bL], R[bL] - l + 1), get(s[bR], 0, r - L[bR] + 1);
    for (int i = 1;; i++) {
      if (k > t[i] + prb[i][bR - 1] - prb[i][bL]) {
        k -= (t[i] + prb[i][bR - 1] - prb[i][bL]);
      } else {
        for (int j = L[i];; ++j)
          if (k > cnt[j] + pre[j][bR - 1] - pre[j][bL]) {
            k -= (cnt[j] + pre[j][bR - 1] - pre[j][bL]);
          } else {
            ans = j;
            break;
          }
        break;
      }
    }
  }
  ans--;
  for (int i = 0; i <= top; i++) {
    t[bl(st[i])] = 0, cnt[st[i]] = 0;
  }
}
inline void change(int x, int v) {
  const int bel = bl(x);
  int las = modify(s[bel], x - L[bel], v);
  for (int i = bel; i <= blc; i++) {
    --pre[las][i], --prb[bl(las)][i], ++pre[v][i], ++prb[bl(v)][i];
  }
}
inline void ins(int x, int v) {
  const int bel = bl(x);
  auto it = s[bel].begin();
  for (int i = x - L[bel]; i--;) ++it;
  s[bel].insert(it, v);
  for (int i = bel; i <= blc; i++) {
    ++pre[v][i], ++prb[bl(v)][i];
  }
  for (int i = bel + 1; i <= blc; i++) {
    if (s[i - 1].size() <= S) {
      break;
    } else {
      int las = s[i - 1].back();
      --pre[las][i - 1], --prb[bl(las)][i - 1];
      s[i - 1].pop_back(), s[i].push_front(las);
    }
  }
}
signed main() {
#ifdef _WIN64
  freopen("testdata.in", "r", stdin);
#else
  ios_base ::sync_with_stdio(false);
  cin.tie(nullptr), cout.tie(nullptr);
#endif
  // code begin.
  in >> n;
  rep(i, 1, blc) { L[i] = R[i - 1] + 1, R[i] = L[i] + S - 1; }
  rep(i, 1, n) {
    int x;
    const int bel = bl(i);
    in >> x, ++x, s[bel].pb(x);
    rep(j, bel, blc) { ++pre[x][j], ++prb[bl(x)][j]; }
  }
  in >> m;
  while (m--) {
    char c;
    in >> c;
    if (c == 'Q') {
      int l, r, k;
      in >> l >> r >> k, qry(l ^ ans, r ^ ans, k ^ ans), out << ans << '
';
    }
    if (c == 'M') {
      int x, v;
      in >> x >> v, x ^= ans, v ^= ans, ++v, change(x, v);
    }
    if (c == 'I') {
      int x, v;
      in >> x >> v, x ^= ans, v ^= ans, ++v, ins(x, v);
    }
  }
  return 0;
  // code end.
}