主席树【可持久化线段树】
\(OI\) 👴 \(hjt\) 发明的,所以叫主席树
可持久化线段树
所谓可持久化,其实就是保存了历史版本信息,类似前缀和的一种信息。
但是其实就是每次都进行单点修改,区间修改的话还没有见识过。
好像是有这样的题目,以后再学。
每次更新一条链,在动态开点的时候复制之前节点的信息,然后再继续开点
代码其实很好写
/*
* @Author: zhl
* @Date: 2020-10-12 19:34:06
*/
#include<bits/stdc++.h>
#define rep(i,a,b) for(int i = a;i <= b;i++)
#define mid (l+r>>1)
using namespace std;
const int N = 5e5 + 10;
int L[N << 5], R[N << 5], sum[N << 5];
int tot;
int build(int l, int r) {
int u = ++tot;
sum[u] = 0;
if (l < r) {
L[u] = build(l, mid);
R[u] = build(mid + 1, r);
}
return u;
}
int insert(int pre, int l, int r, int pos) {
int u = ++tot;
L[u] = L[pre];
R[u] = R[pre];
sum[u] = sum[pre] + 1;
if (l >= r)return u;
if (pos <= mid) {
L[u] = insert(L[pre], l, mid, pos);
}
else {
R[u] = insert(R[pre], mid + 1, r, pos);
}
return u;
}
int query(int rt_x, int rt_y, int l, int r, int k) {
if (l == r) {
return r;
}
int num = sum[L[rt_y]] - sum[L[rt_x]];//区间内,左半区间的数的数量
if (num >= k) {
//在左边
return query(L[rt_x], L[rt_y], l, mid, k);
}
else {
return query(R[rt_x], R[rt_y], mid + 1, r, k - num);
}
}
int n, m;
int A[N], id[N], root[N];
int main() {
cin >> n >> m;
rep(i, 1, n) {
cin >> A[i];
id[i] = A[i];
}
sort(id + 1, id + 1 + n);
int cntID = unique(id + 1, id + 1 + n) - id - 1;
root[0] = build(1, cntID);
rep(i, 1, n) {
int pos = lower_bound(id + 1, id + 1 + cntID, A[i]) - id;
root[i] = insert(root[i - 1], 1, cntID, pos);
}
rep(i, 1, m) {
int x, y, k;
cin >> x >> y >> k;
int pos = query(root[x - 1], root[y], 1, cntID, k);
cout << id[pos] << endl;
}
}
搞一个主席树维护就可以
/*
* @Author: zhl
* @Date: 2020-10-13 09:13:50
*/
#include<bits/stdc++.h>
#define mid (l+r>>1)
using namespace std;
const int N = 5e5 + 10;
int L[N << 5], R[N << 5], sum[N << 5], tot;
int id[N], A[N], root[N];
int build(int l, int r) {
int u = ++tot;
if (l == r) {
sum[u] = A[l];
return u;
}
L[u] = build(l, mid);
R[u] = build(mid + 1, r);
sum[u] = sum[L[u]] + sum[R[u]];
return u;
}
int updt(int v, int l, int r, int pos, int val) {
int u = ++tot;
L[u] = L[v];
R[u] = R[v];
if (l == r) {
sum[u] = val;
return u;
}
if (pos <= mid) {
L[u] = updt(L[v], l, mid, pos, val);
sum[u] = sum[L[u]] + sum[R[u]];
}
else {
R[u] = updt(R[v], mid + 1, r, pos, val);
sum[u] = sum[L[u]] + sum[R[u]];
}
return u;
}
int clone(int v, int l, int r, int pos) {
int u = ++tot;
L[u] = L[v];
R[u] = R[v];
sum[u] = sum[v];
if (l >= r) {
printf("%d\n", sum[v]);
return u;
}
if (pos <= mid) clone(L[v], l, mid, pos);
else clone(R[v], mid + 1, r, pos);
return u;
}
int n, m;
int v, op, loc, val;
int main() {
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; i++) {
scanf("%d", A + i);
}
root[0] = build(1, n);
for (int i = 1; i <= m; i++) {
scanf("%d%d", &v, &op);
if (op == 1) {
scanf("%d%d", &loc, &val);
root[i] = updt(root[v], 1, n, loc, val);
}
else {
scanf("%d", &loc);
root[i] = clone(root[v], 1, n, loc);
}
}
}