可持久化数据结构
好多细节啊,细节能不能爬出 OI。
可持久化线段树
做相关题目的时候注意一下空间。设一个线段树存储的值域为
-
思路是对于每次操作都新建一个线段树,修改直接新建相应下标的那条路径,查询直接查询相应下标即可。注意修改的时候要新建节点并将这个节点返回。注意输入输出优化。
点击查看代码
#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define mid (l + r >> 1)
#define lowbit(x) (x & -x)
const int N = 1e6 + 5, M = 2e7 + 3e6 + 5;
int n, m, lst, opt, k, x;
int val[N], rt[N];
struct Segment_Tree {
int cnt = 1;
struct Node { int l, r, val; } a[M];
void build(int p, int l, int r) {
if (l == r) { a[p].val = val[l]; return ; }
a[p].l = ++cnt; build(cnt, l, mid);
a[p].r = ++cnt; build(cnt, mid + 1, r);
}
int update(int p, int l, int r, int k, int val) {
a[++cnt] = a[p]; p = cnt;
if (l == r) { a[p].val = val; return p; }
if (k <= mid) a[p].l = update(a[p].l, l, mid, k, val);
else a[p].r = update(a[p].r, mid + 1, r, k, val);
return p;
}
int query(int p, int l, int r, int k) {
if (l == r) return a[p].val;
if (k <= mid) return query(a[p].l, l, mid, k);
else return query(a[p].r, mid + 1, r, k);
}
} ST;
signed main() {
cin >> n >> m;
for (int i = 1; i <= n; ++i) scanf("%d", &val[i]);
rt[0] = 1; ST.build(1, 1, n);
for (int i = 1; i <= m; ++i) {
scanf("%d%d", &lst, &opt);
if (opt == 1) { scanf("%d%d", &k, &x); rt[i] = ST.update(rt[lst], 1, n, k, x); }
else { scanf("%d", &k); rt[i] = rt[lst]; printf("%d\n", ST.query(rt[i], 1, n, k)); }
}
return 0;
}
-
可持久化线段树模板题。
思路是建立可持久化值域线段树。对于第
个数,都记一个 存储 对应的值域线段树的根。同样也注意一下空间。非离散化版本:
点击查看代码
#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define mid (l + r >> 1)
#define lowbit(x) (x & -x)
const int N = 2e5 + 5, M = 6e6 + 2e5 + 5;
int n, m, l, r, k;
int val[N], rt[N];
struct Segment_Tree {
int cnt = 1;
struct Node { int l, r, sum; } a[M];
void push_up(int p) {
a[p].sum = a[a[p].l].sum + a[a[p].r].sum;
}
int update(int p, int l, int r, int k) {
a[++cnt] = a[p]; p = cnt;
if (l == r) { ++a[p].sum; return p; }
if (k <= mid) a[p].l = update(a[p].l, l, mid, k);
else a[p].r = update(a[p].r, mid + 1, r, k);
push_up(p); return p;
}
int query(int pl, int pr, int l, int r, int k) {
if (l == r) return l;
if (a[a[pr].l].sum - a[a[pl].l].sum >= k) return query(a[pl].l, a[pr].l, l, mid, k);
return query(a[pl].r, a[pr].r, mid + 1, r, k - (a[a[pr].l].sum - a[a[pl].l].sum));
}
} ST;
signed main() {
cin >> n >> m;
for (int i = 1; i <= n; ++i) { cin >> val[i]; rt[i] = ST.update(rt[i - 1], 0, 1e9, val[i]); }
while (m--) {
cin >> l >> r >> k;
cout << ST.query(rt[l - 1], rt[r], 0, 1e9, k) << endl;
}
return 0;
}
离散化版本:
点击查看代码
#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define mid (l + r >> 1)
#define lowbit(x) (x & -x)
const int N = 2e5 + 5, M = 4e6 + 5;
int n, m, l, r, k;
int p[N], val[N], rt[N];
void lsh(int a[], int n) {
vector<int> v;
for (int i = 1; i <= n; ++i) v.push_back(a[i]);
sort(v.begin(), v.end());
v.erase(unique(v.begin(), v.end()), v.end());
for (int i = 1; i <= n; ++i) {
int res = lower_bound(v.begin(), v.end(), a[i]) - v.begin() + 1;
p[res] = a[i]; a[i] = res;
}
}
struct Segment_Tree {
int cnt = 1;
struct Node { int l, r, sum; } a[M];
void push_up(int p) {
a[p].sum = a[a[p].l].sum + a[a[p].r].sum;
}
int update(int p, int l, int r, int k) {
a[++cnt] = a[p]; p = cnt;
if (l == r) { ++a[p].sum; return p; }
if (k <= mid) a[p].l = update(a[p].l, l, mid, k);
else a[p].r = update(a[p].r, mid + 1, r, k);
push_up(p); return p;
}
int query(int pl, int pr, int l, int r, int k) {
if (l == r) return l;
if (a[a[pr].l].sum - a[a[pl].l].sum >= k) return query(a[pl].l, a[pr].l, l, mid, k);
return query(a[pl].r, a[pr].r, mid + 1, r, k - (a[a[pr].l].sum - a[a[pl].l].sum));
}
} ST;
signed main() {
cin >> n >> m;
for (int i = 1; i <= n; ++i) cin >> val[i];
lsh(val, n);
for (int i = 1; i <= n; ++i) rt[i] = ST.update(rt[i - 1], 1, n, val[i]);
while (m--) {
cin >> l >> r >> k;
cout << p[ST.query(rt[l - 1], rt[r], 1, n, k)] << endl;
}
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律