題目鏈接:https://www.luogu.org/problemnew/show/P3919
主席樹模板題,學了下主席樹的模板
主席樹的核心思想是每次儲存下來每次單點修改之後的線段樹的數據,但這樣肯定會mle,所以有一個優化的方法:因爲每次只更新一個點,那麼在這個線段樹裏只有這個點所在的那一條鏈可能會修改,也就是說我們只要記錄這一條鏈就足夠了,其他的數據我們只要記錄這個版本是從哪個版本修改而來即可,空間複雜度是(4 + n)logn。
#include<bits/stdc++.h>
using namespace std;
const int maxn = (int) (1e6 + 5);
int a[maxn],n,rt[maxn]; //rt爲版本號
struct pstree
{
struct pst
{
int lch,rch,val;
}z[maxn];
int cnt; // 節點個數
inline void build(int &p, int l, int r) // 建樹
{
p = ++cnt; // 版本號
if (l == r)
{
z[p].val = a[l];
return;
}
int mid = (l + r) >> 1;
build(z[p].lch, l, mid); // 左兒子是哪個版本
build(z[p].rch, mid + 1, r); // 右兒子是哪個版本
}
inline void insert(int &p, int pre, int l, int r, int q, int v) // 更新後插入
{
p = ++cnt; // 版本號
z[p] = z[pre]; // 將當前版本初始化與前一個版本相同
if (l == r)
{
z[p].val = v;
return;
}
int mid=(l + r) >> 1;
if (q <= mid)
insert(z[p].lch, z[pre].lch, l, mid, q, v); //更新左兒子
else
insert(z[p].rch, z[pre].rch, mid + 1, r, q, v); // 更新右兒子
}
inline int query (int p, int l, int r, int q) // 查找
{
if (l == r)
return z[p].val;
int mid=(l + r) >> 1;
if (q <= mid)
return query(z[p].lch, l, mid, q); // 在左兒子中找
else
return query(z[p].rch, mid + 1, r, q); // 在右兒子中找
}
}pstree;
int main()
{
// freopen("in.txt", "r", stdin);
int m;
scanf("%d%d", &n, &m);
for(int i = 1; i <= n; ++i)
scanf("%d", &a[i]);
pstree.build(rt[0], 1, n);
for (int i = 1; i <= m; ++i)
{
int p,f,x;
scanf("%d%d%d", &p, &f, &x);
if (f == 1)
{
int v;
scanf("%d", &v);
pstree.insert(rt[i], rt[p], 1, n, x, v);
}
if (f == 2)
{
int tmp = pstree.query(rt[p], 1, n, x);
printf("%d\n", tmp);
rt[i] = rt[p];
}
}
}