我了个大cao,总算调完了
emm,感觉线段树套treap还是非常好写的
我又双叒叕在空间计算上栽坑了QAQ
如果加垃圾回收,那么空间就是 ,但如果不加垃圾回收,我们假设所有的操作都是删除,那么最多新开 个节点,所以空间应为 的。
查询排名为 的数需要二分答案 ,我一开始非常愚蠢地每次查询一遍 的 然后判断是否满足 ,其中 表示比 小的数的个数,显然这么做的常数是非常大的……有一个聪明的做法,就是一旦 就让 ,否则 ,最后返回 ,至于为什么很容易想懂。
#include <cstdio>
#include <cstdlib>
const int N = 50005, M = 1700005, INF = 0x7fffffff;
int cnt, siz[M], ch[M][2], val[M], num[M], rnd[M], a[N], root[N<<2], n;
int read() {
int x = 0, f = 1;
char c = getchar();
while (c < '0' || c > '9') {
if (c == '-') f = -1;
c = getchar();
}
while (c >= '0' && c <= '9') {
x = (x << 3) + (x << 1) + (c ^ 48);
c = getchar();
}
return x * f;
}
int max(int x, int y) {
if (x >= y) return x; return y;
}
int min(int x, int y) {
if (x <= y) return x; return y;
}
void newNode(int &cur, int x) {
cur = ++cnt;
siz[cur] = num[cur] = 1;
val[cur] = x, rnd[cur] = rand();
}
int cmp(int cur, int x) {
cnt;
if (val[cur] == x) return -1;
return x < val[cur] ? 0 : 1;
}
void maintain(int cur) {
siz[cur] = num[cur] + siz[ch[cur][0]] + siz[ch[cur][1]];
}
void rotate(int &cur, int k) {
int fa = ch[cur][k^1];
ch[cur][k^1] = ch[fa][k], ch[fa][k] = cur;
maintain(cur), maintain(fa), cur = fa;
}
void insert(int &cur, int x) {
if (!cur) newNode(cur, x);
else {
int k = cmp(cur, x);
if (k == -1) ++num[cur];
else {
insert(ch[cur][k], x);
if (rnd[ch[cur][k]] > rnd[cur]) rotate(cur, k ^ 1);
}
maintain(cur);
}
}
void del(int &cur, int x) {
int k = cmp(cur, x);
if (k == -1) {
if (num[cur] > 1) --num[cur];
else {
if (!ch[cur][0]) cur = ch[cur][1];
else if (!ch[cur][1]) cur = ch[cur][0];
else {
int kk = rnd[ch[cur][0]] < rnd[ch[cur][1]] ? 0 : 1;
rotate(cur, kk), del(ch[cur][kk], x);
}
}
} else del(ch[cur][k], x);
maintain(cur);
}
int rank(int cur, int x) { //比x小的数的个数
if (!cur) return 0;
if (x == val[cur]) return siz[ch[cur][0]];
if (x < val[cur]) return rank(ch[cur][0], x);
return rank(ch[cur][1], x) + siz[ch[cur][0]] + num[cur];
}
int pre(int cur, int x) {
if (!cur) return -INF;
if (val[cur] >= x) return pre(ch[cur][0], x);
return max(val[cur], pre(ch[cur][1], x));
}
int suf(int cur, int x) {
if (!cur) return INF;
if (val[cur] <= x) return suf(ch[cur][1], x);
return min(val[cur], suf(ch[cur][0], x));
}
//----- Adorable Line -----
void build(int cur, int l, int r, int p, int x) {
insert(root[cur], x);
if (l == r) return;
int mid = l + (r - l >> 1);
if (p <= mid) build(cur << 1, l, mid, p, x);
else build(cur << 1 | 1, mid + 1, r, p, x);
}
int Rank(int cur, int l, int r, int L, int R, int x) {
if (L <= l && r <= R) return rank(root[cur], x);
int mid = l + (r - l >> 1), res = 0;
if (L <= mid) res += Rank(cur << 1, l, mid, L, R, x);
if (mid < R) res += Rank(cur << 1 | 1, mid + 1, r, L, R, x);
return res;
}
int Kth(int L, int R, int x) {
int l = 0, r = 1e8, res = 0;
while (l <= r) {
int mid = l + (r - l >> 1);
int rk = Rank(1, 1, n, L, R, mid);
if (rk < x) l = mid + 1, res = mid;
else r = mid - 1;
}
return res;
}
void update(int cur, int l, int r, int p, int x) {
del(root[cur], a[p]);
insert(root[cur], x);
if (l == r) return;
int mid = l + (r - l >> 1);
if (p <= mid) update(cur << 1, l, mid, p, x);
else update(cur << 1 | 1, mid + 1, r, p, x);
}
int Pre(int cur, int l, int r, int L, int R, int x) {
if (L <= l && r <= R) return pre(root[cur], x);
int mid = l + (r - l >> 1), res = -INF;
if (L <= mid) res = Pre(cur << 1, l, mid, L, R, x);
if (mid < R) res = max(res, Pre(cur << 1 | 1, mid + 1, r, L, R, x));
return res;
}
int Suf(int cur, int l, int r, int L, int R, int x) {
if (L <= l && r <= R) return suf(root[cur], x);
int mid = l + (r - l >> 1), res = INF;
if (L <= mid) res = Suf(cur << 1, l, mid, L, R, x);
if (mid < R) res = min(res, Suf(cur << 1 | 1, mid + 1, r, L, R, x));
return res;
}
int main() {
n = read(); int m = read();
for (int i = 1; i <= n; ++i) a[i] = read(), build(1, 1, n, i, a[i]);
while (m--) {
int opt = read();
if (opt == 1) {
int l = read(), r = read(), x = read();
printf("%d\n", Rank(1, 1, n, l, r, x) + 1);
} else if (opt == 2) {
int l = read(), r = read(), x = read();
printf("%d\n", Kth(l, r, x));
} else if (opt == 3) {
int p = read(), x = read();
update(1, 1, n, p, x); a[p] = x;
} else if (opt == 4) {
int l = read(), r = read(), x = read();
printf("%d\n", Pre(1, 1, n, l, r, x));
} else {
int l = read(), r = read(), x = read();
printf("%d\n", Suf(1, 1, n, l, r, x));
}
}
return 0;
}