左偏樹是一棵二叉樹,也是一種可並堆,擁有堆的性質,可以像堆一樣合併。
左偏樹顧名思義,有「左偏」的特點,既每個左子樹節點的\(dist\)一定大於等於右子樹節點的\(dist\)。
由性質2可得:\(t[x].d=t[t[x].ch[1]].d+1\)
同時,我們需要注意左偏樹的\(dist\)並不意味著深度,跟深度無關。
講了這麼久\(dist\),那麼\(dist\)到底是什麼?
對於乙個二叉樹,我們定義乙個節點的\(dist\)為它到離它最近的葉子節點的距離+1,葉子節點的\(dist=1\),空節點的\(dist=0\)
詳細見**注釋
int& rs(int x)//求右兒子
找到\(x\)所在堆的最小值/最大值,用並查集實現,接著合併\(x\)的左右子樹
int find(int x)
void pop(int &x)
注意:這裡是刪除任意編號節點,而不是任意權值節點,左偏樹不支援刪除任意權值節點
我們先合併\(x\)的左右兒子
接著更新\(x\)的父親和\(f[x]\)的兒子
因為這樣合併更新可能會破壞左偏的性質,所以需要遍歷檢查滿不滿足左偏性質,更新,直到滿足左偏性質就可以結束或者到達根節點
void pushup(int x)
}int merge(int x,int y)
void del(int x)
新建乙個節點,將其初始化為\(x\)
因為這個節點也可以視為乙個堆,可以直接合併
void push(int &rt,int v)
在根\(x\)上打標記,然後每一次合併堆或者刪除根時下傳
void pushdown(int x)//這裡以加上乙個數為例
}
模板題洛谷p3377 【模板】左偏樹(可並堆)
洛谷p2713 羅馬遊戲
給出洛谷p2713 羅馬遊戲的**
#includeusing namespace std;
const int n=1000010;
struct tree
t[n];
int n,q;
int f[n];
bool dead[n];
int& rs(int x)
int find(int a)
char op[10];
int main()
scanf("%d",&q);
while(q--)
else
a=find(a);
dead[a]=1;
f[a]=f[t[a].ch[0]]=f[t[a].ch[1]]=merge(t[a].ch[0],t[a].ch[1]);
printf("%d\n",t[a].val);
} }return 0;
}
例題
【xsy1985】【bzoj1367】【baltic2004】sequence
【xsy2488】【hdu5818】joint stacks
深深感覺到自己的渺小
左偏樹 模板
神經病也可以寫成右偏樹 具體左偏指左節點的距離 geq 右節點的距離 距離指離最近擁有空節點的節點的距離 乙個節點的值一定 或 leq 或 geq 或 其子節點的值 由於左偏性質,每次可以合併至右邊,維護左偏性質後就可以保證複雜度 被踩爆的板子 或者是我?include define ls lson...
模板 左偏樹
洛谷模板題 一聽左偏樹這個名字就感覺左偏。左偏樹是什麼,好像就是個堆,大根堆或小根堆,可以支援合併,取堆頂元素,刪除堆頂元素,插入元素的操作。一些說明 左偏樹節點除了應有的東西,還有鍵值和距離,鍵值用於比較大小,距離是什麼?距離是這樣定義的 節點i稱為外節點 external node 當且僅當節點...
模板 左偏樹
可在log複雜度合併的堆 每個節點有乙個距離,具體定義我不知道 1.滿足堆的性質 2.左子節點距離 右子節點 3.節點距離 右子節點距離加1 按照以上的性質實現merge x,y 先選出x,y中比較大的那個 大根堆為例 再拿它的右兒子和另乙個去merge,如果merge出來不符合性質2就swap一下...