可持久化fhq-treap學習筆記
阿新 • • 發佈:2018-12-01
目錄
可持久化fhq-treap----- 支援查詢歷史版本的非旋treap
luogu扣圖:
先看看為啥他可以可持久化
由於fhq-Treap是沒有旋轉操作的
所以每次操作後的其它沒有操作的節點間的關係不變
而有旋轉平衡樹是要改變的,所以就不大能進行可持久化了
過程
回想,主席樹的方法:
每次用log的記憶體記錄一次操作
這可持久平衡樹也一樣
每次merge或者split都新開節點記錄路徑
路徑是log級的,所以記憶體也在nlogn的級別(當然不是nlog,是操作log)
還是用結構體吧,容易賦值
其實也就是加了幾句話
其實也就是和主席樹差不多
其實也沒啥說的,看程式碼去吧
別的
SovietPower:一點(很小的)優化? 操作3.4.5.6都不會改原樹,root[i]=root[ver]可以直接賦值,不需要再Merge了
xx:為什麼
SovietPower:容易發現,你的合併操作的記憶體都是新開的,但你這一次操作(是opt的操作辣)是沒有改變任何值,所以你直接用上一次的就好,拆開的記憶體不用管就好
注意&&出錯&&吐槽
我們擷取merge函式的一部分
if(e[x].pri<e[y].pri) {
int p=++cnt;
e[p]=e[x];
rs(p)=merge(rs(p),y);
pushup(p);
return p;
}
}
那是不是可以寫成
if(e[x].pri<e[y].pri) { int p=++cnt; e[p]=e[x]; rs(p)=merge(rs(p),y); pushup(p); return p; }
當然是不對的啊,你還要遞迴呢,cnt當然要變化了
這陣列模擬記憶體有點多呀,指標應該就沒這毛病了,不過我還是學不下去指標233
模板->luoguP3835程式碼
#include <iostream>
#include <ctime>
#include <cstdlib>
#include <cstdio>
#include <cstring>
#define ls(x) e[x].ls
#define rs(x) e[x].rs
#define FOR(i,a,b) for(int i=a;i<=b;++i)
using namespace std;
const int maxn=500007;
const int inf=0x7fffffff;
int read() {
int x=0,f=1;char s=getchar();
for(;s>'9'||s<'0';s=getchar()) if(s=='-') f=-1;
for(;s>='0'&&s<='9';s=getchar()) x=x*10+s-'0';
return x*f;
}
struct node {
int ls,rs,size,val,pri;
}e[maxn*50];
int cnt,rt[maxn*50];
void pushup(int x) {
e[x].size=e[ls(x)].size+e[rs(x)].size+1;
}
int make_edge(int x) {
e[++cnt].val=x;
e[cnt].size=1;
e[cnt].pri=rand();
return cnt;
}
int merge(int x,int y) {
if(!x||!y) return x+y;
if(e[x].pri<e[y].pri) {
int p=++cnt;
e[p]=e[x];
rs(p)=merge(rs(p),y);
pushup(p);
return p;
}
else {
int p=++cnt;
e[p]=e[y];
ls(p)=merge(x,ls(p));
pushup(p);
return p;
}
}
void split(int now,int k,int &x,int &y) {
if(!now) x=y=0;
else {
if(e[now].val<=k) {
e[x=++cnt]=e[now];
split(rs(now),k,rs(x),y);
pushup(x);
}
else {
e[y=++cnt]=e[now];
split(ls(now),k,x,ls(y));
pushup(y);
}
}
}
inline int k_th(int now,int k) {
while(233) {
if(k==e[ls(now)].size+1) return now;
if(k<=e[ls(now)].size) now=ls(now);
else k-=e[ls(now)].size+1,now=rs(now);
}
}
int main() {
int n=read(),x,y,z;
FOR(i,1,n) {
int tim=read(),opt=read(),a=read();
rt[i]=rt[tim];
if(opt==1) {
split(rt[i],a,x,y);
rt[i]=merge(merge(x,make_edge(a)),y);
} else if(opt==2) {
split(rt[i],a,x,z);
split(x,a-1,x,y);
y=merge(ls(y),rs(y));
rt[i]=merge(merge(x,y),z);
} else if(opt==3) {
split(rt[i],a-1,x,y);
printf("%d\n",e[x].size+1);
rt[i]=merge(x,y);
} else if(opt==4) {
printf("%d\n",e[k_th(rt[i],a)].val);
} else if(opt==5) {
split(rt[i],a-1,x,y);
if(e[x].size) {
printf("%d\n",e[k_th(x,e[x].size)].val);
rt[i]=merge(x,y);
}
else printf("%d\n",-inf);
} else {
split(rt[i],a,x,y);
if(e[y].size) {
printf("%d\n",e[k_th(y,1)].val);
rt[i]=merge(x,y);
}
else printf("%d\n",inf);
}
}
return 0;
}