二逼平衡树

码量稍微有大,不过思路清晰还是好写的

题目链接

外层线段树,内层平衡树

操作1 4 5就是在线段树上取出区间,然后平衡树内求答案,合并答案

修改也没什么好讲的,和上一题比较相似

操作2要二分答案,然后转化为1

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
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185


Author: zxy_hhhh
date: 2018/12/03
*/

#include<cstring>
#include<algorithm>
#include<cctype>
#include<cmath>
#define rep(x,a,b) for (int x=int(a);x<=(int)(b);x++)
#define drp(x,a,b) for (int x=int(a);x>=(int)(b);x--)
#define cross(x,a) for (int x=hd[a];x;x=nx[x])
#define ll long long
using namespace std;
inline ll ()
{
ll _x=0;int _ch=getchar(),_f=1;
for(;!isdigit(_ch)&&(_ch!='-')&&(_ch!=EOF);_ch=getchar());
if (_ch=='-'){_f=0;_ch=getchar();}
for(;isdigit(_ch);_ch=getchar()) _x=_x*10+_ch-'0';
return _f?_x:-_x;
}
void write(ll _x){if (_x>=10) write(_x/10),putchar(_x%10+'0'); else putchar(_x+'0'); }
inline void wrt(ll _x,char _p){if (_x<0) putchar('-'),_x=-_x; write(_x); if (_p) putchar(_p);}
#define maxn 50005
#define inf 2147483647
#define mid ( (l + r) >> 1
int a[maxn], n, m;
namespace xtree {
struct node *nil;
struct node {
int sz, val, fix;
node *ls, *rs;
node(int x) : sz(1), val(x), fix(rand()) { ls = rs = nil; }
inline void update() { sz = ls->sz + rs->sz + 1; }
};
inline void init() {
nil = new node(0);
nil->ls = nil->rs = nil;
nil->sz = 0;
}
void split(node *now, int k, node *&x, node *&y, int op = 1) {
if (now == nil) {
x = y = nil;
return;
}
if (op == 1 ? now->val < k : now->ls->sz < k) {
x = now;
split(now->rs, (op == 1 ? k : k - now->ls->sz - 1), x->rs, y, op);
x->update();
} else {
y = now;
split(now->ls, k, x, y->ls, op);
y->update();
}
}
node *merge(node *x, node *y) {
if (x == nil) return y;
if (y == nil) return x;
if (x->fix < y->fix) {
x->rs = merge(x->rs, y);
return x->update(), x;
} else {
y->ls = merge(x, y->ls);
return y->update(), y;
}
}
inline void insert(node *&rt, int val) {
node *x, *y;
split(rt, val, x, y);
rt = merge(x, merge(new node(val), y));
}
inline void del(node *&rt, int val) {
node *x, *y, *z;
split(rt, val, x, y);
split(y, 1, y, z, 2);
rt = merge(x, z);
}
inline int pre(node *&rt, int val) {
node *x, *y, *z;
int ans;
split(rt, val, x, y), split(x, x->sz - 1, x, z, 2);
if (z == nil)
ans = -inf;
else
ans = (z->val);
rt = merge(x, merge(z, y));
return ans;
}
inline int nxt(node *&rt, int val) {
node *x, *y, *z;
int ans;
split(rt, val + 1, x, y), split(y, 1, y, z, 2);
if (y == nil)
ans = inf;
else
ans = y->val;
rt = merge(x, merge(y, z));
return ans;
}
inline int rank(node *&rt, int val) {
node *x, *y;
int ans;
split(rt, val, x, y);
if (x == nil)
ans = 0;
else
ans = x->sz;
rt = merge(x, y);
return ans;
}
} // namespace xtree
namespace ytree {
xtree::node *tr[maxn << 2];
inline int pre(int pos, int l, int r, int ql, int qr, int x) {
if (r < ql || l > qr) return -inf;
if (ql <= l && r <= qr) return x = xtree::pre(tr[pos], x);
return max(pre(pos << 1, l, mid, ql, qr, x),
pre(pos << 1 | 1, mid + 1, r, ql, qr, x));
}
inline int nxt(int pos, int l, int r, int ql, int qr, int x) {
if (r < ql || l > qr) return inf;
if (ql <= l && r <= qr) return x = xtree::nxt(tr[pos], x);
return min(nxt(pos << 1, l, mid, ql, qr, x),
nxt(pos << 1 | 1, mid + 1, r, ql, qr, x));
}
inline int rank(int pos, int l, int r, int ql, int qr, int x) {
if (r < ql || l > qr) return 0;
if (ql <= l && r <= qr) return x = xtree::rank(tr[pos], x);
return rank(pos << 1, l, mid, ql, qr, x) +
rank(pos << 1 | 1, mid + 1, r, ql, qr, x);
}
inline void change(int pos, int l, int r, int x, int v) {
xtree::del(tr[pos], a[x]), xtree::insert(tr[pos], v);
if (l == r) return;
if (x <= mid)
change(pos << 1, l, mid, x, v);
else
change(pos << 1 | 1, mid + 1, r, x, v);
}
inline int atrank(int L, int R, int k) {
int l = 0, r = 100000000, ans;
while (l <= r) {
if (rank(1, 1, n, L, R, mid) < k)
ans = mid, l = mid + 1;
else
r = mid - 1;
}
return ans;
}
void build(int pos, int l, int r) {
tr[pos] = xtree::nil;
rep(i, l, r) xtree::insert(tr[pos], a[i]);
if (l == r) return;
build(pos << 1, l, mid), build(pos << 1 | 1, mid + 1, r);
}
} // namespace ytree
int main() {
n = rd();
m = rd();
xtree::init();
rep(i, 1, n) a[i] = rd();
ytree::build(1, 1, n);
rep(i, 1, m) {
int op = rd();
if (op == 1) {
int l = rd(), r = rd(), x = rd();
wrt(ytree::rank(1, 1, n, l, r, x) + 1, 'n');
} else if (op == 2) {
int l = rd(), r = rd(), x = rd();
wrt(ytree::atrank(l, r, x), 'n');
} else if (op == 3) {
int x = rd(), k = rd();
ytree::change(1, 1, n, x, k);
a[x] = k;
} else if (op == 4) {
int l = rd(), r = rd(), x = rd();
wrt(ytree::pre(1, 1, n, l, r, x), 'n');
} else if (op == 5) {
int l = rd(), r = rd(), x = rd();
wrt(ytree::nxt(1, 1, n, l, r, x), 'n');
}
}
}