洛谷P3919可持久化线段树
P3919 【模板】可持久化數組(可持久化線段樹/平衡樹)
- 題目提供者HansBug?站長團
- 評測方式云端評測
- 標簽O2優化高性能
- 難度提高+/省選-
- 時空限制3000ms / 512MB
有了可持久化數組,便可以實現很多衍生的可持久化功能(例如:可持久化并查集)
題目描述
如題,你需要維護這樣的一個長度為?N 的數組,支持如下幾種操作
在某個歷史版本上修改某一個位置上的值
訪問某個歷史版本上的某一位置的值
此外,每進行一次操作(對于操作2,即為生成一個完全一樣的版本,不作任何改動),就會生成一個新的版本。版本編號即為當前操作的編號(從1開始編號,版本0表示初始狀態數組)
輸入格式:
輸入的第一行包含兩個正整數 N M, 分別表示數組的長度和操作的個數。
第二行包含 N 個整數,依次為初始狀態下數組各位的值(依次為 ai?,1 ≤ i ≤ N)。
接下來 M行每行包含 3 或 4 個整數,代表兩種操作之一( i 為基于的歷史版本號):
????? ? 1.對于操作1,格式為 vi?1 loci?valuei,即為在版本 vi?的基礎上,將 aloci?修改為 valuei。
????? ? 2.對于操作2,格式為 vi?2 loci,即訪問版本 vi?中的 aloci?的值。
(1 <= N,M <= 105,1 <= loci?<= N,1 <= vi?<= i,- 109?<= ai,valuei?<= 109)
輸出格式:
輸出包含若干行,依次為每個操作2的結果。
輸入
5 10 59 46 14 87 41 0 2 1 0 1 1 14 0 1 1 57 0 1 1 88 4 2 4 0 2 5 0 2 4 4 2 1 2 2 2 1 1 5 91輸出
59 87 41 87 88 46說明
樣例說明:
一共11個版本,編號從0-10,依次為:
*?0?: 59 46 14 87 41
*?1?: 59 46 14 87 41
*?2?: 14 46 14 87 41
*?3?: 57 46 14 87 41
*?4?: 88 46 14 87 41
*?5?: 88 46 14 87 41
*?6?: 59 46 14 87 41
*?7?: 59 46 14 87 41
*?8?: 88 46 14 87 41
*?9?: 14 46 14 87 41
*?10?: 59 46 14 87 91
可持久化線段樹
給出 N 個數字的序列,M 次操作。
有兩個操作: 1. 更新 i 點元素為 k,并保存版本 +1。
? ? ? ? ? ? ? ? ? ? ? ?2. 查詢 x 版本下點 i 的值。 起初為版本號為 0。
可持久化線段樹最大的特點是:
可以訪問歷史版本。 簡而言之,可持久化線段樹,是在線段樹上不斷更新,但卻 不刪除原有信息的線段樹。 每次更新都賦予一個新的根節點編號,用以區分不同的版本。
由于可持續化線段樹的結點的序號不確定。 因此需要采取動態開點的方法構建線段樹
#include <bits/stdc++.h> using namespace std; const int maxn = 1e5 + 10; struct node{int lc,rc;long long int v; }segtree[maxn << 8];//可持久化線段樹 int root[maxn << 5];//root[i]表示版本號為i的線段樹的根節點編號 long long int a[maxn];//長度為 N 的數組 int n,m;//n個點,m種操作 int tot;int build_tree(int l, int r) {int pos = ++tot;if (l == r) {segtree[pos].v = a[l];return pos;}int mid = l + (r - l)/2;segtree[pos].lc = build_tree(l, mid);segtree[pos].rc = build_tree(mid + 1, r);return pos; } //即訪問版本 pos 中的 a[p] 的值 long long int query(int pos, int p, int l, int r) {if (l == r) {return segtree[pos].v;}int mid = l + (r - l)/2;if(p <= mid) return query(segtree[pos].lc, p, l, mid);else return query(segtree[pos].rc, p, mid + 1, r); } //在版本 old 的基礎上,將 a[tar] 修改為 c int update(int old, int tar, int c, int l, int r) {int pos = ++tot;//新開節點時,需要依靠前面構建的節點編號+1if (l == r) {segtree[pos].v = c;return pos;}segtree[pos].lc = segtree[old].lc;segtree[pos].rc = segtree[old].rc;int mid = l + (r - l)/2;if(tar <= mid) segtree[pos].lc = update(segtree[old].lc, tar, c, l, mid);else segtree[pos].rc = update(segtree[old].rc, tar, c, mid + 1, r);return pos; }int main() {//freopen("test.in", "r", stdin);//freopen("test.out", "w", stdout);while (scanf("%d %d", &n, &m) != EOF) {tot = 0;for (int i = 1;i <= n; i++){scanf("%lld", &a[i]);}root[0] = build_tree(1,n);int v,x,l,w;for (int i = 1;i <= m; i++){scanf("%d %d %d", &v, &x, &l);if (x == 1) {scanf("%d", &w);root[i] = update(root[v], l, w, 1, n);} else {root[i] = root[v];printf("%lld\n",query(root[v], l, 1, n));}}}return 0; }?
總結
以上是生活随笔為你收集整理的洛谷P3919可持久化线段树的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: HDU1166 敌兵布阵 单点更新
- 下一篇: 图的存储 邻接矩阵+邻接表+链式前向星