zoj_2243笛卡爾樹的構造,開始被topcoder上的教程吸引去看這題。題目中說這種資料結構叫treap然後就按照treap的insert加上左旋右旋去做了,結果果斷tle。然後網上找了一下關於笛卡爾樹的資料,發現了一些問題的端倪。
其次,我們可以看到,在zoj_2243中,如果使用treap,按照題意乙個個插如節點,隨即化就被打破了,judge系統的資料也許不隨機,從而導致treap的鏈化,弱化了平衡性,理想的nlogn的複雜度,可能退化到n^2,導致最後的tle(可能左旋右旋操作的消耗也對應能有所影響).
最後,找到了一種排序之後直接構造笛卡爾樹的方法。首先將節點序列按照key從小到大排序,然後按照順序插入節點,注意到排序之後,插入的節點的key值一定是樹中最大的,所以只需查詢最右端的路徑,找到乙個節點a[i]的value大於待插入節點的value,同時a[i]->right的value小於待插入節點的value。找到之後,只需將a[i]的right指向待插入的節點,a[i]的right原來指向的節點賦值給待插入節點的left指標。注意到查詢最右路徑的方向,如果從下到上查詢,複雜度比較容易分析o(n)(因為查詢過的節點必然會旋轉到某個節點的左子節點,因此每個查詢過的節點只會被查詢一次),如果從上倒下,比較複雜(和最右端的最終的路徑長度有關吧),會超過n,甚至更高,可能為o(n^2)。
另外,找到一種使用排序加左旋的方法,就是一樣先排序,然後使用treap插入節點,可以發現,所有的旋轉都為左旋。這種方法也tle了,這種方法有乙個很重要的意義,就是分析了上個方法中從上到下掃瞄的複雜度。因為這兩種方法的效率是等價的,都tle。
最後,同樣的題zoj是5m的,poj是2m的,我用了從上到下2.5s,從下到上0.6s。
**zoj_2243
#include#include#include#include#includeusing namespace std;
class treap_node
};class treap
void treap_left_rotate(treap_node*&a)
void treap_right_rotate(treap_node*&a)
void treap_insert(treap_node*&a,string label,int p)
else if(labellabel)
else
}void plist(treap_node*a)
} };int num;
treap_node n[50001];
bool cmp(const treap_node&n1,const treap_node&n2)
if(pre==null)
else
} return;
}int main()
sort(n,n+num,cmp);
//for(int i=0;itreap_insert(p->root,n[i].label,n[i].p);
insertn(p->root);
p->plist(p->root);
cout<} return 0;
}
pat笛卡爾樹
笛卡爾樹是一種特殊的二叉樹,其結點包含兩個關鍵字k1和k2。首先笛卡爾樹是關於k1的二叉搜尋樹,即結點左子樹的所有k1值都比該結點的k1值小,右子樹則大。其次所有結點的k2關鍵字滿足優先佇列 不妨設為最小堆 的順序要求,即該結點的k2值比其子樹中所有結點的k2值小。給定一棵二叉樹,請判斷該樹是否笛卡...
笛卡爾樹小結
粗略的學習了一下笛卡爾樹 主要是為了平衡樹打基礎吧 因為關於平衡樹 treap 早忘了 splay 不信任複雜度 然後 我能學一種比較簡單的樹y 笛卡爾樹.這裡以建出小根堆為例。描述區間性質的樹 可以當成二叉搜尋樹不過並不平衡因為每次都是選取當前區間最小值當做為根 然後顯然根據區間的數的排列不同樹的...
笛卡爾樹學習筆記
笛卡爾樹學習筆記 笛卡爾樹是一種二叉樹,每乙個結點由乙個鍵值二元組 k,w 構成。要求 k 滿足二叉搜尋樹的性質,而 w 滿足堆的性質。乙個有趣的事實是,如果笛卡爾樹的 k,w 鍵值確定,且 k 互不相同,w 互不相同,那麼這個笛卡爾樹的結構是唯一的 在一般情況下,未說明 k 時,我們預設 k 為下...