【Kubernetes系列一】kubernetes1.12安裝
阿新 • • 發佈:2022-04-15
可持久化資料結構是可以修改和查詢任意歷史版本的資料結構。
而其中,最簡單的“資料結構”非陣列莫屬了。
設有一題,一個數組,單點修改,單點查詢,不過要求在任意歷史版本為基礎修改,查詢任意歷史版本中的某個元素。
一看資料範圍,10^6,暴力可以哦豁了。
彳亍吧,那就得另闢蹊徑了
既然只是單點修改,其他的n-1個點沒有被改過呀!於是可持久化資料結構應運而生。如果版本2相比版本1,只是一個元素的差異,那麼只需要儲存版本1,以及多出來的版本2的那一個元素,就OK了
那怎麼聯絡這一個元素,與版本1呢?
如題,用線段樹。
線段樹怎麼用呢?
就像下面這樣用
畫得太好了
橙色代表版本2,黑色代表版本1。
橙樹的左兒子與黑樹左兒子重合(因為版本2的左半區間沒有修改),橙色右兒子的左兒子是它唯一的獨立葉節點(因為這個點代表的元素被修改過),所有橙色的獨立節點代表的區間都被修改過。
所有的節點有且只有2個兒子,所有節點可能不只有1個父節點
所以,一定需要存的是每個版本的修改內容(從根節點下拉一條鏈),空間複雜度\Theta(\log_nq+n)。為了防止空間複雜度退化至\Theta(n\times q),實現時需要動態開點。
結構體?與動態開點一致
struct stree{
int lc,rc;
int dat;
建樹?照著動態開點寫就可以了(到這裡與可持久化沒有關係)
void build(int &now,int l,int r){
now=++tot;
if(l==r){
dat(now)=a[l];
return;
}
int mid=(l+r)>>1;
build(lc(now),l,mid);
build(rc(now),mid+1,r);
}
修改?這裡就是重頭戲了。除了標準的動態開點,還需要一個引數來連線該版本中未修改的其他部分與原版本。
那就再次回到這個圖
顯然,要在某個版本的基礎上進行修改,必先把與之重合的節點複製一遍,至於其他點,就各自新建一個節點就好啦。
void change(int &now,int las,int o,int l,int r,int val){
now=++tot;
//新建節點
dat(now)=dat(las);
lc(now)=lc(las);rc(now)=rc(las);
//複製節點
if(l==r){dat(now)=val;return;}
int mid=(l+r)>>1;
if(o<=mid)change(lc(now),lc(las),o,l,mid,val);
else change(rc(now),rc(las),o,mid+1,r,val);
//遞迴建整樹
}
int ask(int now,int l,int r,int o){
if(l==r)return dat(now);
int mid=(l+r)>>1;
if(o<=mid)return ask(lc(now),l,mid,o);
else return ask(rc(now),mid+1,r,o);
}