例題
luogu 3919
特點:在普通線段樹支援查詢當前狀態基礎上,支援查詢過去的所有版本
一、\(\text\):
暴力儲存過去版本,每一次修改都會造成\(nlogn\)的時空複雜度,總複雜度\(o\)(\(mnlogn\)),直接上天
注意到每一次單點修改只會導致對應的葉子節點以及它的所有祖先儲存的值改變,我們可以考慮只儲存這一條鏈,將這條鏈連到原來的樹上,單次時空複雜度\(logn\)
每次修改一定會影響根節點,所以每次修改都會換乙個新的根,並且可以看出,由每個根向下都可以遍歷出一顆形狀完全相同的線段樹,所以每個根直接對應自己的版本,訪問乙個版本直接從這個根向下就行了
注:可持久化線段樹要存左右兒子,不能直接2或者2+1表示左右兒子
二、\(\text\)
線段樹其他所有操作不變(除了根節點變了),只影響查詢操作
查詢向下遞迴的過程中,每到乙個點,申請乙個新節點\(t\),其資訊和當前點完全相同,然後繼續向下,如果向左遞迴就將左兒子修改為左邊即將有的新節點編號,右兒子不變,如果右遞迴則相反。回溯時同樣也需要\(pushup\)
\(luogu\) 3919
\(code\)
這道題只有單點查詢,不需要維護中間節點,只需要維護葉子節點的值就行了,實際上進一步削弱了難度(甚至不需要這個演算法(霧))
#include#define n 6000005
using namespace std;
int n,m;
int a[n];
int root[n],sum[n*4],ls[n*4],rs[n*4],ndsum;
template void read(t &x)
void build(int &rt,int l,int r)//初始建樹
int mid=(l+r)>>1;
build(ls[rt],l,mid);
build(rs[rt],mid+1,r);
}void copynode(int x,int y)//複製
int modify(int rt,int l,int r,int x,int v)//一次修改
int mid=(l+r)>>1;
if(mid>=x) ls[t]=modify(ls[rt],l,mid,x,v);//左邊
else rs[t]=modify(rs[rt],mid+1,r,x,v);//右邊
return t;//返回這個點的編號
}int query(int rt,int l,int r,int x)
int main()
else
}return 0;
}
可持久化線段樹學習筆記
模板 includeusing namespace std const int n 2e5 10 int cnt,rt n int n,a n t n t int ls n 20 rs n 20 dat n 20 void copy int x,int y int build int l,int r...
可持久化線段樹學習筆記
可持久化,即對資料修改後仍可查詢到其歷史版本。以模板題為例 p3919 模板 可持久化線段樹 1 可持久化陣列 單點修改 查詢的可持久化。暴力時空複雜度 o nm 版本複製 m 修改查詢 可持久化線段樹 時空複雜度只為 o m log n n 題解口胡 建乙個陣列hed存各版本的對應的線段樹根 對於...
可持久化線段樹學習筆記
可持久化是真的毒瘤,在網上找了很多資料才搞懂 不過我覺得應該是我太蒻了 首先以洛谷上的兩個板子題為例吧 對於第一題,要求詢問區間第k大 第k大指的是從小到大排序的第k個 直接掃是肯定不行的,因此我們需要可持久化線段樹 感覺跳的好快,但是我也不清楚要怎麼表達,就這樣吧,反正知道是要用這個就行了 首先既...