1. 程式人生 > >笛卡爾樹的妙用

笛卡爾樹的妙用

兩個 進棧 二叉 clas sta 擁有 logs 查找 一個

前言

笛卡爾樹,其實是一顆treap,每個節點擁有兩個值,key值和val值。key值是這個節點本身的大小值,在一顆treap中滿足二叉查找樹的性質,而val值則是一個隨機值,學過treap的同學都知道,這個val值是拿來使得樹的層高是期望log的,val值滿足堆的性質,這裏以小根堆為例講解(當然大根堆不會有任何問題)。

應用

一般笛卡爾樹都被用來建一顆treap,復雜度為O(n)的,n表示插入的元素個數。
而暴力插入的話是O(n log n)的。
這裏需要講清楚的是,笛卡爾樹建樹,插入的元素必須保證key值遞增,而val值是可以亂的,許多博客裏沒有講,這裏必須要強調一下。

實現

我們維護笛卡爾樹的極右鏈,就是根,根的右兒子,根的右兒子的右兒子.......
放在一個棧裏,棧底是根,這樣很顯然從棧頂到棧底,val值是不斷變小的。
每當我們進入一個新的節點,我們從棧頂開始找,當找到第一個節點的val值比我小,那麽我必須得是它的兒子,而我的key值又比他大,所以我作為它的右兒子,而原先它的右兒子key值比我小,所以作為我的左兒子,這樣就維護了一個treap的性質,然後原來那些點變為了我的左兒子,所以就要從極右鏈中刪掉,我加入到極右鏈中,這樣每個點進棧一次,出棧一次,復雜度就是O(n)的,下面貼出具體的代碼。

for (int i=1;i<=n;i++){
        read(key[i]),val[i]=rand();
        while (top&&val[i]<val[stack[top]]){
            rson[stack[top]]=last;
            last=stack[top];
            lson[i]=stack[top];
            top--;
        }
        if (top) rson[stack[top]]=i;
        stack[++top]=i;
    }

以上就是笛卡爾樹線性建treap的全部過程,希望對大家的學習有幫助

笛卡爾樹的妙用