主席树维护每个点的前缀权值情况.
树状数组维护区间.
想法比较直观, 联赛的教训是想到了要能快写.
#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;
}
线段树套平衡树写法
等待填坑.