可持久化线段树就是可以查询和修改历史版本的线段树
具体实现:
- 我们采用动态开点的方式来建立线段树
- build和query操作与普通动态开点线段树如出一辙
- 对于修改操作,我们新增修改后的结点及其父结点,未修改过的结点直接copy过来
- 对于一次修改,就是一次新增祖宗的过程,也是一次添加新版本的过程
题目链接:可持久化线段树 1各变量含义:
t[i] - i所表示区间的权值
lson[p] - p结点左儿子所在位置
rson[p] - p结点右儿子所在位置
v[i] - 版本i起始结点所在位置
cnt - 下一个新增结点所在位置
a - 原数组
change函数中:p - 历史版本,q - 新版本
#includeusing namespace std; int t[20000020], lson[20000020], rson[20000020], v[10000020], cnt = 2, a[10000005]; void build(int p, int l, int r) { if (l == r) { t[p] = a[l]; } else { lson[p] = cnt++; rson[p] = cnt++; int m = l + r >> 1; build(lson[p], l, m); build(rson[p], m + 1, r); t[p] = t[lson[p]] + t[rson[p]]; } } void change(int p, int q, int l, int r, int x, int d) { if (r < x || l > r) { lson[q] = lson[p]; rson[q] = rson[p]; } else if (l == r && l == x) { t[q] = d; } else { lson[q] = lson[p]; rson[q] = rson[p]; int m = l + r >> 1; if (x <= m) { lson[q] = cnt++; change(lson[p], lson[q], l, m, x, d); } else { rson[q] = cnt++; change(rson[p], rson[q], m + 1, r, x, d); } t[q] = t[lson[q]] + t[rson[q]]; } } int query(int p, int l, int r, int ql, int qr) { if (l > qr || r < ql) { return 0; } else if (ql <= l && r <= qr) { return t[p]; } else { int m = l + r >> 1; return query(lson[p], l, m, ql, qr) + query(rson[p], m + 1, r, ql, qr); } } int main() { ios::sync_with_stdio(false); cin.tie(0); cout.tie(0); int n, m; cin >> n >> m; for (int i = 1; i <= n; i++) { cin >> a[i]; } build(1, 1, n); v[0] = 1; for (int i = 1; i <= m; i++) { int vi, op, x, d; cin >> vi >> op; if (op == 1) { cin >> x >> d; v[i] = cnt++; change(v[vi], v[i], 1, n, x, d); } else { cin >> x; v[i] = v[vi]; cout << query(v[vi], 1, n, x, x) << endl; } } return 0; }



