模板树套树.

树状数组套主席树

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

树状数组维护区间.

想法比较直观.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
#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;
}

线段树套平衡树

等待填坑.