可持久化陣列

2022-02-19 16:22:11 字數 1475 閱讀 1798

日常不想放題目

luogu p3919 【模板】可持久化陣列

題目中要求可以查詢歷史狀態,最暴力的想法是開\(a[m][n]\)的二維陣列,每次修改暴力複製並修改,每次查詢暴力掃瞄,時間複雜度是\(o(m*n)\)的,但這顯然是不行的.

這個時候其實很容易想到線段樹,但線段樹維護的是當前狀態而無法維護歷史狀態,一種暴力的想法是開\(m\)棵線段樹,但這樣\(mle\)的風險可謂巨大。

舉個例子:

乙個六個資料的線段樹

初始數值: 0 4 0 7 0 3(發現沒什麼用

建成一棵線段樹:

假設我們要修改第二個位置,那麼被修改的也就是橙色部分:

所以可以只新建這一部分節點:

於是樹就變成了這個亞子(

因為需要不斷的新建節點,因此不能按照常規的\(k<<1,k<<1|1\)來記錄線段樹的兒子,而需要開專門的陣列來記錄左右兒子的編號;

我們只需要記錄每次修改後的根節點\(rt[i]\),在查詢第\(v\)次操作時順著\(rt[v]\)查詢就好

具體實現不是很難(這是我第一次自己按思想自己寫出來的資料結構

#includeusing namespace std;

inline int read() const int mxn=1000010;

int n,m,a[mxn];

int cntn,rt[mxn<<5];

struct node t[mxn<<5];

int build(int l,int r)

int mid=(l+r)>>1;

t[now].l=build(l,mid);

t[now].r=build(mid+1,r);

return now;

}int modify(int k,int l,int r,int x,int p)

int mid=(l+r)>>1;

if(x<=mid)

t[now].l=modify(t[k].l,l,mid,x,p),t[now].r=t[k].r;

else

t[now].r=modify(t[k].r,mid+1,r,x,p),t[now].l=t[k].l;

return now;

}int query(int k,int l,int r,int x)

int main()

if(opt==2)

} return 0;

}

可持久化陣列

update 最後乙個點時間空間已經放大 標題即題意 有了可持久化陣列,便可以實現很多衍生的可持久化功能 例如 可持久化並查集 如題,你需要維護這樣的乙個長度為 nn 的陣列,支援如下幾種操作 在某個歷史版本上修改某乙個位置上的值 訪問某個歷史版本上的某一位置的值 此外,每進行一次操作 對於操作2,...

模板 可持久化陣列

戳我 為了方便起見,處理的陣列長度為5,起始的陣列元素為1 5,修改是將第乙個位置的陣列元素改為2。建樹規則很簡單,只要在葉子節點上寫上該點的值就可以了。我們發現,這兩棵線段樹中只有乙個葉子節點的值發生了改變,而運算元非常多,假如每次都memset一下,然後修改乙個值,空間上的巨大開銷幾乎無法想象,...

可持久化專題(二) 可持久化陣列的實現

前言 呃,首先宣告,看這篇部落格前,最好先去學一學主席樹,畢竟可持久化陣列的實現是完全基於主席樹的 那些亂七八糟的玄學演算法請走開 l in klink link 主席樹詳見部落格可持久化專題 一 主席樹 可持久化線段樹 順便吐槽一句,可持久化陣列這個名字聽起來真的很智障。簡介 可持久化陣列支援單點...