P3919 【模板】可持久化陣列(可持久化線段樹/平衡樹)
阿新 • • 發佈:2018-12-10
主席樹模板題,學了下主席樹的模板
主席樹的核心思想是每次儲存下來每次單點修改之後的線段樹的資料,但這樣肯定會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]; } } }