1. 程式人生 > >學習總結:Dsu on tree 樹上啟發式合併

學習總結:Dsu on tree 樹上啟發式合併

(RT,這只是一篇小小的總結,以便將來的回顧,並不詳細講)

以前也學習過啟發式合併,大概就是像樹形dp一樣在dfs上,將兒子的資訊向父親轉移,容器是map,將兒子的資訊邊轉移邊更新答案,轉移之後便將兒子的容器清空,防止空間超限。不過對於本人而言,雖然思路較為簡便,但是因為有用到map的迭代器,所以這種寫法寫起來較為繁瑣。

最近學了一種基於dfs序的一種的啟發式合併,特點就是:暴力。
看似暴力。

演算法的流程大概是這樣:
1、dfs將一棵樹建好,將節點的size、dfs序、重兒子、該dfs序對應的節點這些資訊處理好(其他的資訊具體問題具體分析)。
2、進入solve函式,先去解決非重兒子,然後將這些非重兒子的資訊暴力清空。
3、接下來解決重兒子,這次不清空。
4、然後再將非重兒子的資訊再暴力新增。
5、將該節點的資訊新增進容器。
6、回答關於這個節點的問題。
7、返回。
注意:這裡的新增是利用dfs序進行的。

流程還是有點繁瑣,那就看程式碼吧。

void build(int p,int pre,int d){
    sz[p]=1;
    dep[p]=d;
    l[p]=++dfn;
    f[dfn]=p;
    for(int i=0;i<e[p].size();i++){
        int v=e[p][i];
        build(v,p,d+1);
        sz[p]+=sz[v];
        if(sz[v]>sz[son[p]])son[p]=v;
    }
    r[p]=dfn;
}
void del(int p){
    for
(int i=l[p];i<=r[p];i++)sum[dep[f[i]]]--; } void ins(int p){ for(int i=l[p];i<=r[p];i++)sum[dep[f[i]]]++; } void solve(int p){ int to=son[p]; for(int i=0;i<e[p].size();i++){ int nx=e[p][i]; if(nx!=to)solve(nx),del(nx); } if(to)solve(to); if(!p)return; for
(int i=0;i<e[p].size();i++){ int nx=e[p][i]; if(nx!=to)ins(nx); } sum[dep[p]]++; for(int i=0,sz=ask[p].size();i<sz;i++)ans[ask[p][i].id]=sum[ask[p][i].k]-1; }

相信看到程式碼的時候就在想,這不是暴力嗎?
這其實和普通的啟發式合併的核心是一樣的:普通的啟發式合併的複雜度是O(nlogn),是因為每次合併是將小集合併到大集合,對於小集合來說,合併後,集合的size至少擴大到原來的2倍,那麼合併的次數一定小於等於logn。然後看有n個點,所以所有點合併的次數就是nlogn。考慮在map合併自帶的複雜度,以及清空記憶體的複雜度,這樣近似暴力的啟發式合併的複雜度也就近似O(nlogn)了。
同理,每一個重兒子合併的次數也是logn。
所以Dsu on tree的複雜度同樣是近似O(nlogn)。

當然對於存資訊的sum不一定是普通的陣列,可能是map,可能是樹狀陣列這類既支援插入又支援刪除的容器,有適合的資料結構,而不是用資料結構去套題。

這種演算法能夠解決關於詢問一棵樹的子樹的相關資訊的問題。
當然,演算法是好的,關鍵是在足夠理解的基礎上能夠用起來!

相關推薦

學習總結Dsu on tree 樹上啟發式合併

(RT,這只是一篇小小的總結,以便將來的回顧,並不詳細講) 以前也學習過啟發式合併,大概就是像樹形dp一樣在dfs上,將兒子的資訊向父親轉移,容器是map,將兒子的資訊邊轉移邊更新答案,轉移之後便將兒子的容器清空,防止空間超限。不過對於本人而言,雖然思路較為簡

dsu on tree 樹上啟發式合併 學習筆記

近幾天跟著dreagonm大佬學習了\(dsu\ on\ tree\),來總結一下: \(dsu\ on\ tree\),也就是樹上啟發式合併,是用來處理一類離線的樹上詢問問題(比如子樹內的顏色種數)的不二法寶。它不僅好想好寫,還有著\(O(nlogn)\)的優秀時間複雜度(劃重點)。 結合一道例題來講吧:

[CF600E]Lomsat gelral[dsu on tree/樹上啟發式合併]

題意:求每個節點子樹眾數和(比如3和5都是眾數 答案是8) 樹上啟發式合併可以解決一些無修改的子樹詢問 先solve輕兒子,後solve重兒子,如果該節點是輕兒子,然後重新統計輕兒子的貢獻,更新該節點的答案,如果該節點是輕兒子,那麼將該節點的貢獻刪除,回溯(其實就是保留了重兒子的答案) 由於輕重鏈剖分一

dsu on tree (樹上啟發式合併) 詳解

**一直都沒出過演算法詳解,昨天心血來潮想寫一篇,於是 dsu on tree 它來了** ## 1、前置技能 >1.鏈式前向星(vector 建圖) > >2.dfs 建樹 > >3.剖分輕重鏈,輕重兒子 | 重兒子 | 一個結點的所有兒子中擁有最多子樹的兒子 | | :----: | :------

dsu on tree 樹上啟發式合並 學習筆記

for 時間 奇數 優化 遞歸 復雜度 數組 當前 編號 近幾天跟著dreagonm大佬學習了\(dsu\ on\ tree\),來總結一下: \(dsu\ on\ tree\),也就是樹上啟發式合並,是用來處理一類離線的樹上詢問問題(比如子樹內的顏色種數)的不二法寶。它不

BZOJ.3307.雨天的尾巴(dsu on tree/線段樹合併)

BZOJ 洛谷 \(dsu\ on\ tree\)。(線段樹合併的做法也挺顯然不寫了) 如果沒寫過\(dsu\)可以看這裡。 對修改操作做一下差分放到對應點上,就成了求每個點子樹內出現次數最多的顏色,這就和CF600E類似了。直接用\(dsu\)。 修改某個顏色出現次數的時候,最大值不能\(O(1)\)求

圖論-樹上啟發式合並(DSU On Tree)

pac code include clu 修改 += disjoint namespace std Disjoint Set Union On Tree ,似乎是來自 Codeforces 的一種新操作,似乎被叫做“樹上啟發式合並”。 在不帶修改的有根樹子樹信息統計問題中,

【CF 600 E】Lomsat gelral——樹上啟發式合併dsu on tree入門

一.前言: 這次講解的dsu on tree,其實是一種優美的暴力,它的時間複雜度分析與樹鏈剖分類似,也需要用到重兒子這一概念(不會樹剖的點這裡). 這種演算法適用於一類樹上查詢子樹的問題,不過它只能處理有子樹查詢的問題,不支援修改,也不支援鏈查詢. 二.例題:

[BZOJ2599][IOI2011]Race-樹上啟發式合併(dsu on tree)

Race Description 給一棵樹,每條邊有權.求一條簡單路徑,權值和等於K,且邊的數量最小.N <= 200000, K <= 1000000 Input 第一行 兩個整數 n, k 第二..n行 每行三個整數 表示一條無

樹上啟發式合併 DSU On Tree

前言 這個演算法是退役之後才知道的…… 大概作用是支援靜態的樹上的一些對子樹資訊的離線詢問。 和樹上莫隊很像,也是按照一個順序來處理詢問,要求在外部能較快速地維護當前選入點的資訊。 和樹鏈剖分很像,也是先找出重兒子和輕兒子,兩種按一定次序處理,也因此保證

dsu on tree總結

int 什麽 小寫 啟發式 上啟 char pro esp 存在 dsu on tree 樹上啟發式合並。我並不知道為什麽要叫做這個名字。。。 幹什麽的 可以在\(O(n\log n)\)的時間內完成對子樹信息的詢問,可橫向對比把樹按\(dfs\)序轉成序列問題的\(O(n

樹上統計treecnt(dsu on tree 並查集 正難則反)

problem freopen space script type 題目 每次 分割 pos 題目鏈接 \(Description\) 給定一棵\(n(n\leq 10^5)\)個點的樹。 定義\(Tree[L,R]\)表示為了使得\(L\sim R\)號點兩兩連通,最少需

Codeforces 600E dsu on tree 啟發式合併

題目:傳送門 題意: 給一顆樹,計算所有結點的子樹,顏色最多的結點的 顏色種類的sum和,子樹的定義是當前結點和其所有的子節點。 題解: 我們可以想到一種暴力的解法,就是O(n)遍歷所有的結點,然後d

dsu on tree 啟發式合併演算法

我們先引入這樣一個問題: 有一棵樹,樹上有很多結點,每個結點有一個顏色c,我們現在想知道樹上每個結點的子樹**(subtree)**,有多少個結點出現顏色c。子樹的定義:該結點和其所有的孩子構成的樹。

Atcoder #017 agc017 D.Game on Tree 樹上NIM 博弈

不為 gmail ace first n) long long let fin 模板 LINK 題意:樹上NIM的模板題,給出一顆樹,現有操作刪去端點不為根節點的邊,其另一端節點都將被移除,不能取者為敗 思路:一看就是個NIM博弈題,只是搬到樹上進行,樹上DFS進行

dsu on tree

pen try trie樹 奇數 ans play upd music isa osu on tree? dsu on tree! 這種操作可以在O(nlogn)的時間內解決一些無修改子樹詢問問題。 咱知道把一棵樹輕重鏈剖分後,樹的輕鏈,重鏈都只有O(logn)個。 這個算

基本數據結構學習總結 二叉樹的遍歷

root 取出 後序 二叉 isnull 就是 bre 遞歸 use 二叉搜索樹的遍歷 二叉樹遍歷的內容很多,但是也是最重要的,最需要理解的,很多二叉樹的相關算法,只要用活了遍歷就沒有問題了 前序遍歷 對於每一棵樹,先遍歷其根節點,然後遍歷其左子樹,最後用同樣的方式遍歷

初涉DSU on tree

ref 16px one 就是 後來 大量 == 我們 註意 早先以為莫隊是個頂有用的東西,不過好像樹上莫隊(不帶修)被dsu碾壓? dsu one tree起源 dsu on tree是有人在cf上blog上首發的一種基於輕重鏈剖分的算法,然後好像由因為這個人

Codeforces Round #383 (Div. 1): D. Arpa’s letter-marked tree…(dsu on tree+狀壓)

  題意: 給你一棵n個節點的樹,每條邊都代表著一個字母(a~v),對於每個節點u,求出以u為根的子樹中有多少條路徑滿足:路徑上的字元重新排列後可以得到一個迴文字串   思路: 前置:dsu on tree 然後就可以思考該怎麼O(n²)暴

dsu on tree(Educational Codeforces Round 2: E. Lomsat gelral)

  題意: 一棵n個節點的樹,每個節點都有一種顏色,如果顏色c在以u為根的子樹中出現的次數大於等於一半,那麼這個顏色就是u節點的支配色, 因為是大於等於,所以一個節點的支配色可能不止一種,求出每個節點的支配色編號和   思路: 一個無腦的暴力: