【模板】可持久化陣列
阿新 • • 發佈:2019-02-16
可持久化陣列是由可持久化線段樹或可持久化平衡樹實現的。這裡先給出可持久化線段樹的實現方法。
為了方便起見,處理的陣列長度為5, 起始的陣列元素為1~5,修改是將第一個位置的陣列元素改為2。
建樹規則很簡單,只要在葉子節點上寫上該點的值就可以了。
先根據原陣列建一棵線段樹
第一次修改之後的線段樹
我們發現,這兩棵線段樹中只有一個葉子節點的值發生了改變,而運算元非常多,假如每次都memset一下,然後修改一個值,空間上的巨大開銷幾乎無法想象,那我們可以設想一下,把兩個線段樹“合併一下”……
把兩次線段樹合併的結果
這下我們的思路就很清楚了。每次對某個歷史版本進行修改時,對於所有包含該位置的區間結點全部新開一個,並與其父節點連邊,對於其他結點,由於不需要發生改動,所以直接連線即可。
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<vector>
#define maxn 2000005
int n, m, p, x, y, lastans;
int a[maxn];
inline int getint() {
int num = 0, sign = 1;
char ch = getchar();
while (ch < '0' || ch > '9' ) {
ch == '-' ? sign = -1 : 1;
ch = getchar();
}
while (ch >= '0' && ch <= '9')
num = (num << 3) + (num << 1) + (ch ^ '0'),
ch = getchar();
return num * sign;
}
struct Rope { //想不出有什麼好名字,,由於c++STL中有支援可持久化的陣列rope,就把名字搬過來了。
static const int MAXSIZE = 2000005;
int cnt, value[MAXSIZE << 4];
int root[MAXSIZE << 4], lc[MAXSIZE << 4], rc[MAXSIZE << 4];
void build(int &k, int l, int r) { //build
k = ++cnt; //由於結點數目並不固定,採取陣列模擬連結串列而不是類似堆的儲存方式儲存一棵線段樹
if (l == r) {
value[k] = a[l];
return;
}
int mid = (l + r) >> 1;
build(lc[k], l, mid);
build(rc[k], mid + 1, r);
}
int query(int k, int l, int r, int pos) {
if (l == r) return value[k];
int mid = (l + r) >> 1;
if (pos <= mid)
return query(lc[k], l, mid, pos);
else return query(rc[k], mid + 1, r, pos);
}
void insert(int x, int &y, int l, int r, int pos, int val) {
y = ++cnt;
if (l == r) {
value[y] = val;
return;
}
int mid = (l + r) >> 1;
lc[y] = lc[x]; rc[y] = rc[x]; //複製左子樹和右子樹,那些需要重開的結點會在接下來的遞迴被修改
if (pos <= mid)
insert(lc[x], lc[y], l, mid, pos, val);
else insert(rc[x], rc[y], mid + 1, r, pos, val);
}
void build(int l, int r) { //build函式過載,主程式中呼叫
build(root[0], l, r);
}
int find(int x, int y, int z) { //find過載
root[z] = root[x];
return query(root[x], 1, n, y);
}
void insert(int x, int y, int pos, int val) { //insert過載
insert(root[x], root[y], 1, n, pos, val);
}
};
Rope array;
int main() {
n = getint(); m = getint();
for (int i = 1; i <= n; i++)
a[i] = getint();
array.build(1, n);
for(int i = 1; i <= m; i++) {
int x = getint(), opt = getint(), y = getint();
if (opt == 1)
array.insert(x, i, y, getint());
else printf("%d\n", array.find(x, y, i));
}
return 0;
}
最後,就不帶模板的粘一下可持久化陣列的模板
由於struct內部有函式過載,有兩個版本。
struct版本
struct Rope {
static const int MAXSIZE = 2000005;
int cnt, value[MAXSIZE << 4];
int root[MAXSIZE << 4], lc[MAXSIZE << 4], rc[MAXSIZE << 4];
void build(int &k, int l, int r) {
k = ++cnt;
if (l == r) {
value[k] = a[l];
return;
}
int mid = (l + r) >> 1;
build(lc[k], l, mid);
build(rc[k], mid + 1, r);
}
int query(int k, int l, int r, int pos) {
if (l == r) return value[k];
int mid = (l + r) >> 1;
if (pos <= mid)
return query(lc[k], l, mid, pos);
else return query(rc[k], mid + 1, r, pos);
}
void insert(int x, int &y, int l, int r, int pos, int val) {
y = ++cnt;
if (l == r) {
value[y] = val;
return;
}
int mid = (l + r) >> 1;
lc[y] = lc[x]; rc[y] = rc[x];
if (pos <= mid)
insert(lc[x], lc[y], l, mid, pos, val);
else insert(rc[x], rc[y], mid + 1, r, pos, val);
}
void build(int l, int r) {
build(root[0], l, r);
}
int find(int x, int y, int z) {
root[z] = root[x];
return query(root[x], 1, n, y);
}
void insert(int x, int y, int pos, int val) {
insert(root[x], root[y], 1, n, pos, val);
}
};
class版本
class Rope {
private:
static const int MAXSIZE = 2000005;
int cnt, value[MAXSIZE << 4];
int root[MAXSIZE << 4], lc[MAXSIZE << 4], rc[MAXSIZE << 4];
void build(int &k, int l, int r) {
k = ++cnt;
if (l == r) {
value[k] = a[l];
return;
}
int mid = (l + r) >> 1;
build(lc[k], l, mid);
build(rc[k], mid + 1, r);
}
int query(int k, int l, int r, int pos) {
if (l == r) return value[k];
int mid = (l + r) >> 1;
if (pos <= mid)
return query(lc[k], l, mid, pos);
else return query(rc[k], mid + 1, r, pos);
}
void insert(int x, int &y, int l, int r, int pos, int val) {
y = ++cnt;
if (l == r) {
value[y] = val;
return;
}
int mid = (l + r) >> 1;
lc[y] = lc[x]; rc[y] = rc[x];
if (pos <= mid)
insert(lc[x], lc[y], l, mid, pos, val);
else insert(rc[x], rc[y], mid + 1, r, pos, val);
}
public:
void build(int l, int r) {
build(root[0], l, r);
}
int find(int x, int y, int z) {
root[z] = root[x];
return query(root[x], 1, n, y);
}
void insert(int x, int y, int pos, int val) {
insert(root[x], root[y], 1, n, pos, val);
}
};