單調棧的應用 笛卡爾樹與虛樹

2022-04-30 06:54:10 字數 2598 閱讀 4494

何為笛卡爾樹?

對於一組關係\(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\)求出來後按照原樹的構造連線成的樹

定理一:

樹中\(k\)個節點之間兩兩之間不同的\(lca\)至多有\(k - 1\)個

證明:使用尤拉序

考慮\(dfs\)序最大的一條鏈

按照\(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上扣...