1. 程式人生 > >【模板】可持久化陣列

【模板】可持久化陣列

戳我

可持久化陣列是由可持久化線段樹或可持久化平衡樹實現的。這裡先給出可持久化線段樹的實現方法。

為了方便起見,處理的陣列長度為5, 起始的陣列元素為1~5,修改是將第一個位置的陣列元素改為2。
建樹規則很簡單,只要在葉子節點上寫上該點的值就可以了。

先根據原陣列建一棵線段樹

這裡寫圖片描述

第一次修改之後的線段樹

這裡寫圖片描述
我們發現,這兩棵線段樹中只有一個葉子節點的值發生了改變,而運算元非常多,假如每次都memset一下,然後修改一個值,空間上的巨大開銷幾乎無法想象,那我們可以設想一下,把兩個線段樹“合併一下”……

把兩次線段樹合併的結果

這裡寫圖片描述
這下我們的思路就很清楚了。每次對某個歷史版本進行修改時,對於所有包含該位置的區間結點全部新開一個,並與其父節點連邊,對於其他結點,由於不需要發生改動,所以直接連線即可。

Code

#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);
        }
};