主席树的最基础的操作就是查询历史版本区间第 大,带修。
这个问题的基础解决思路:对于每次修改都建一棵权值线段树,显然空间开不下。
这时可持久化线段树的思路就应运而生了。
主要思想:
不难发现,每次修改只会有一条链上的值发生改变,所以我们不需要建出整棵新树,只需要把新建那条链上的点即可。
所以空间就是 的。
我们还要在权值线段树上做个前缀和来方便查询,每次查询时,就是在权值线段树上二分的过程。
注意到我们要建的是权值线段树,所以要对输入的值做一个离散化。
不多说了,直接贴代码吧。
#include <bits/stdc++.h> | |
#define uint unsigned int | |
#define ls(x) t[x].l | |
#define rs(x) t[x].r | |
using namespace std; | |
namespace IO{ | |
inline int read(){ | |
int x = 0, f = 1; | |
char ch = getchar(); | |
while(!isdigit(ch)) {if(ch == '-') f = -1; ch = getchar();} | |
while(isdigit(ch)) x = (x << 3) + (x << 1) + ch - '0', ch = getchar(); | |
return x * f; | |
} | |
inline char readc(){ | |
char ch = getchar(); | |
while(ch < 'a' || ch > 'z') ch = getchar(); | |
return ch; | |
} | |
template <typename T> inline void write(T x){ | |
if(x > 9) write(x / 10); | |
putchar(x % 10 + '0'); | |
} | |
} | |
using namespace IO; | |
const int N = 2e5 + 10; | |
int n, m, cnt; | |
int a[N], b[N]; | |
struct Tree{ | |
int rt, sum, l, r; | |
Tree() {sum = 0;} | |
}t[N << 5]; | |
inline int build(int l, int r){ | |
int rt = ++cnt; | |
if(l == r) return rt; | |
int mid = (l + r) >> 1; | |
ls(rt) = build(l, mid); | |
rs(rt) = build(mid + 1, r); | |
return rt; | |
} | |
inline int update(int pre, int l, int r, int x){ | |
int rt = ++cnt; | |
ls(rt) = ls(pre), rs(rt) = rs(pre), t[rt].sum = t[pre].sum + 1; | |
if(l == r) return rt; | |
int mid = (l + r) >> 1; | |
if(x <= mid) ls(rt) = update(ls(pre), l, mid, x); | |
else rs(rt) = update(rs(pre), mid + 1, r, x); | |
return rt; | |
} | |
inline int query(int L, int R, int k, int l, int r){ | |
if(l == r) return l; | |
int res = t[ls(R)].sum - t[ls(L)].sum; | |
int mid = (l + r) >> 1; | |
if(res >= k) return query(ls(L), ls(R), k, l, mid); | |
else return query(rs(L), rs(R), k - res, mid + 1, r); | |
} | |
int main(){ | |
n = read(), m = read(); | |
for(int i = 1; i <= n; ++i) a[i] = read(), b[i] = a[i]; | |
sort(b + 1, b + 1 + n); | |
int tot = unique(b + 1, b + 1 + n) - b - 1; | |
for(int i = 1; i <= n; ++i) | |
a[i] = lower_bound(b + 1, b + 1 + tot, a[i]) - b; | |
t[0].rt = build(1, tot); | |
for(int i = 1; i <= n; ++i) t[i].rt = update(t[i - 1].rt, 1, tot, a[i]); | |
while(m--){ | |
int l = read(), r = read(), k = read(); | |
write(b[query(t[l - 1].rt, t[r].rt, k, 1, tot)]), puts(""); | |
} | |
return 0; | |
} |