何為笛卡爾樹?
對於一組關係\(fa, ls, rs\)
滿足\(pri[fa] \geqslant max(pri[ls], pri[rs])\)
以及\(val[rs] \geqslant val[fa] \geqslant val[ls]\)
如何構建笛卡爾樹?
按照\(val\)順序順序插入\(n\)個點
那麼,新插入的點一定會插入到最右邊(最大)
那麼,我們維護最右鏈
同時,注意到最右鏈中\(pri\)單調
因此可以維護乙個單調棧,來即時地找到插入位置
void tree()
}
建樹的方法2每次選取區間最大值作為根,然後往兩邊遞迴也可以建樹
直接暴力是\(o(n^2)\)的
線段樹優化一下就可以\(o(n \log n)\)了
一些常見的題目:
[hnoi2016]序列
[ioi2018]meeting
luogup4755
cf1117g
[zjoi2012]小藍的好友
在一棵樹中,把給定點及相關的\(lca\)求出來後按照原樹的構造連線成的樹
定理一:考慮\(dfs\)序最大的一條鏈樹中\(k\)個節點之間兩兩之間不同的\(lca\)至多有\(k - 1\)個
證明:使用尤拉序
按照\(dfs\)序排序後,我們嘗試依次加入點\(a\)
那麼,點\(a\)要麼新開一條鏈,要麼對\(dfs\)序最大的鏈產生影響
只要用乙個單調棧來維護當前鏈即可
同時,為了方便,約定退棧連邊
具體而言,有以下幾種情況
我們假設\(v\)是棧頂元素,\(w\)是棧中排第二的元素
\(root\)是\(k\)個點中\(dfs\)序最小的點(即虛樹根),\(lca\)是\(v\)和\(a\)的最近公共祖先
假設原鏈的形式類似於此
第一種情況:
這種情況下,\(v\)退棧,\((v, lca)\)需要被連線,\(lca, a\)依次進棧
第二種情況:
\(a\)直接進棧即可
第三種情況:
\(v\)退棧,\((v, w)\)連線,\(a\)進棧
第四種情況:
\(v\)退棧,\((v, w)\)連線之後情況沒有什麼變化
\(w\)成為新的\(v\),繼續操作直到變為情況1, 3
因此,總結一下步驟
先插入虛樹根給個本人的實現吧....依次插入後\(i\)個點
求出\(a\)與\(v\)的\(lca\)
如果\(lca = v\),跳到第7步
如果\(dfn[w] >= dfn[lca]\),\(v\)退棧,\((v, w)\)連線,重複此步驟
如果\(dfn[w] < dfn[lca]\), \(v\)退棧,\((v, lca)\)連線,\(lca\)入棧
否則\(v\)退棧,\((v, w)\)連線
\(a\)入棧
重複第\(2\)至第\(7\)步
最後處理棧中剩下的最後一條鏈
inline bool cmp(int a, int b)
//dfn陣列為dfs序,dep陣列為節點深度
//h陣列儲存所有的關鍵點,總共有k個
//st為棧
void vitural_tree
while(top > 1 && dep[st[top - 1]] >= dep[rem])
if(dep[st[top]] > dep[rem]) link(rem, st[top]), top --;
if(rem != st[top]) st[++ top] = rem;
if(h[i] != st[top]) st[++ top] = h[i];
}while(top > 1) link(st[top - 1], st[top]), top --;
}
虛樹題目的顯著特徵:\(\sum k \leq 3 * 10^5\)(當然有的時候並不是)
[sdoi2011]消耗戰
[heoi2014]大工程
[hnoi2014]世界樹
pkuwc2019 你和虛樹的故事(不知道什麼時候公開呢....)
虛樹套資料結構:
luogup4242 樹上的毒瘤
動態維護虛樹資訊:
[sdoi2015]尋寶遊戲
真.動態虛樹:(也可能是個假的
bzoj5402 f
TJOI2011 樹的序(貪心,笛卡爾樹)
眾所周知,二叉查詢樹的形態和鍵值的插入順序密切相關。準確的講 1 空樹中加入乙個鍵值k,則變為只有乙個結點的二叉查詢樹,此結點的鍵值即為k 2 在非空樹中插入乙個鍵值k,若k小於其根的鍵值,則在其左子樹中插入k,否則在其右子樹中插入k。我們將一棵二叉查詢樹的鍵值插入序列稱為樹的生成序列,現給出乙個生...
SGU155 笛卡爾樹的構造
分類 資料結構 2013 09 07 20 12 300人閱讀收藏 舉報題目 題意 給出每個點的兩個值key和fix,且所有的key值和fix值都是不相同的,要求構造出笛卡爾樹。輸入每個點的兩個權 值,輸出笛卡爾樹每個結點 按照輸入的順序編號 的父親結點和兩個兒子的編號。分析 首先,笛卡爾樹對於ke...
笛卡爾樹 P2659 美麗的序列
tag笛卡爾樹 找出乙個序列的所有子段中子段長度乘段內元素最小值的最大值。我們需要找出所有子段中貢獻最大的,並且乙個子段的貢獻為其長度乘區間最小值。這 不就是裸的笛卡爾樹嗎?建出符合小根堆性質的笛卡爾樹,遞迴所有點,更新答案即可。因為這是一道裸題,所以我記錄一下建笛卡爾樹的模板。從oi wiki上扣...