日常不想放題目
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 主席樹詳見部落格可持久化專題 一 主席樹 可持久化線段樹 順便吐槽一句,可持久化陣列這個名字聽起來真的很智障。簡介 可持久化陣列支援單點...