[BZOJ 3196][模板] 二(屏蔽)平衡树 - 树状数组套主席树

主席树维护每个点的前缀权值情况.

树状数组维护区间.

想法比较直观, 联赛的教训是想到了要能快写.

#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>

using namespace std;

const int maxn = 3e+5 + 5;
const int maxp = maxn * 50;

struct opt
{
  int typ, a, b, c;
}opl[maxn];
int n, m, lp[maxn], rp[maxn];
int id[maxn], s[maxn];
int ls[maxp], rs[maxp], su[maxp], cnt;
int val[maxn], cpy[maxn], tot;

inline int rd() {
  register int x = 0, f = 0, c = getchar();
  while (!isdigit(c)) {
    if (c == '-') f = 1;
    c = getchar();
  }
  while (isdigit(c)) x = x * 10 + (c ^ 48), c = getchar();
  return f ? -x : x;
}
inline void init(int l, int r) {
  for (; l; l -= (l & -l)) lp[l] = id[l];
  for (; r; r -= (r & -r)) rp[r] = id[r];
}
inline void toLeft(int l, int r) {
  for (; l; l -= (l & -l)) lp[l] = ls[lp[l]];
  for (; r; r -= (r & -r)) rp[r] = ls[rp[r]];
}
inline void toRight(int l, int r) {
  for (; l; l -= (l & -l)) lp[l] = rs[lp[l]];
  for (; r; r -= (r & -r)) rp[r] = rs[rp[r]];
}
inline int getLeft(int x, int *p) {
  int ret = 0; for (; x; x -= (x & -x)) ret += su[ls[p[x]]];
  return ret;
}
int update(int lst, int l, int r, int p, int x) {
  int newrt = ++cnt;
  ls[newrt] = ls[lst]; rs[newrt] = rs[lst];
  su[newrt] = su[lst] + x;
  if (l == r) return newrt;
  int mid = (l + r) >> 1;
  if (p <= mid) ls[newrt] = update(ls[lst], l, mid, p, x);
  else rs[newrt] = update(rs[lst], mid + 1, r, p, x);
  return newrt;
}
int getRank(int l, int r, int L, int R, int x) {
  if (l == r) return 0;
  int mid = (l + r) >> 1;
  if (x <= mid) {
    toLeft(L, R);
    return getRank(l, mid, L, R, x);
  } else {
    int tmp = getLeft(R, rp) - getLeft(L, lp);
    toRight(L, R);
    return getRank(mid + 1, r, L, R, x) + tmp;
  }
}
int getKth(int l, int r, int L, int R, int k) {
  if (l == r) return cpy[l];
  int mid = (l + r) >> 1;
  int tmp = getLeft(R, rp) - getLeft(L, lp);
  if (k <= tmp) {
    toLeft(L, R);
    return getKth(l, mid, L, R, k);
  } else {
    toRight(L, R);
    return getKth(mid + 1, r, L, R, k - tmp);
  }
}
inline void add(int p, int x, int v) {
  for (; p <= n; p += (p & -p)) id[p] = update(id[p], 1, tot, x, v);
}

int main() {
  n = rd(); m = rd();
  for (int i = 1; i <= n; ++i) val[i] = cpy[i] = rd();
  tot = n;
  for (int i = 1; i <= m; ++i) {
    opl[i].typ = rd();
    if (opl[i].typ == 3) {
      opl[i].a = rd();
      opl[i].b = rd();
      cpy[++tot] = opl[i].b;
    } else {
      opl[i].a = rd();
      opl[i].b = rd();
      opl[i].c = rd();
      if (opl[i].typ != 2) cpy[++tot] = opl[i].c;
    }
  }
  sort(cpy + 1, cpy + 1 + tot);
  tot = unique(cpy + 1, cpy + 1 + tot) - (cpy + 1);
  for (int i = 1; i <= n; ++i) {
    int x = lower_bound(cpy + 1, cpy + 1 + tot, val[i]) - cpy;
    add(i, x, 1);
  }
  for (int i = 1; i <= m; ++i) {
    if (opl[i].typ == 3) {
      int pos = opl[i].a, newval = opl[i].b;
      int ori = lower_bound(cpy + 1, cpy + 1 + tot, val[pos]) - cpy;
      int upd = lower_bound(cpy + 1, cpy + 1 + tot, newval) - cpy;
      add(pos, ori, -1);
      val[pos] = newval;
      add(pos, upd, 1);
    } else {
      int ql = opl[i].a - 1, qr = opl[i].b, qv;
      init(ql, qr);
      if (opl[i].typ != 2) qv = lower_bound(cpy + 1, cpy + 1 + tot, opl[i].c) - cpy;
      if (opl[i].typ == 1) printf("%d\n", getRank(1, tot, ql, qr, qv) + 1);
      else if (opl[i].typ == 2) printf("%d\n", getKth(1, tot, ql, qr, opl[i].c));
      else if (opl[i].typ == 4) {
        int k = getRank(1, tot, ql, qr, qv);
        if (!k) puts("-2147483647");
        else {
          init(ql, qr);
          printf("%d\n", getKth(1, tot, ql, qr, k));
        }
      } else {
        int k = getRank(1, tot, ql, qr, qv + 1);
        if (k > opl[i].b - opl[i].a) puts("2147483647");
        else {
          init(ql, qr);
          printf("%d\n", getKth(1, tot, ql, qr, k + 1));
        }
      }
    }
  }
  return 0;
}

线段树套平衡树写法

等待填坑.

猜你喜欢

转载自www.cnblogs.com/nishikino-curtis/p/9998959.html
今日推荐