日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

树上启发式合并

發(fā)布時(shí)間:2023/12/3 编程问答 29 豆豆
生活随笔 收集整理的這篇文章主要介紹了 树上启发式合并 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

文章內(nèi)容選自O(shè)I Wiki
參考博客

內(nèi)容:

樹上啟發(fā)式合并(dsu on tree)對(duì)于某些樹上離線問題可以速度大于等于大部分算法且更易于理解和實(shí)現(xiàn)的算法。
他是用來(lái)解決一類樹上詢問問題,一般這種問題有兩個(gè)特征:

  • 只有對(duì)子樹的詢問
  • 沒有修改
  • 一般就可以簽上dsu on tree

    例題:
    給出一棵 n個(gè)節(jié)點(diǎn)以 1為根的樹,節(jié)點(diǎn) u的顏色為cu ,現(xiàn)在對(duì)于每個(gè)結(jié)點(diǎn) u詢問 u子樹里一共出現(xiàn)了多少種不同的顏色。
    n<=2e5

    樹套樹可以解決,如果可以離線的話,樹上莫隊(duì)復(fù)雜度帶根號(hào),現(xiàn)在我們要用一個(gè)帶log的算法。
    對(duì)于直接暴力復(fù)雜度為O(n^2),即對(duì)每一個(gè)子節(jié)點(diǎn)進(jìn)行一次遍歷,
    對(duì)于每個(gè)節(jié)點(diǎn)的答案是由其子樹和其本身得到的,現(xiàn)在考慮利用這個(gè)性質(zhì)處理問題
    我們預(yù)處理出每個(gè)節(jié)點(diǎn)子樹的大小和其重兒子,重兒子同樹鏈剖分一樣,都是擁有節(jié)點(diǎn)最多子樹的兒子,這個(gè)過(guò)程O(n)求
    用cnt[i]表示顏色i出現(xiàn)的次數(shù),ans[u]表示節(jié)點(diǎn)u的答案
    對(duì)于一個(gè)節(jié)點(diǎn)u,我們按以下步驟遍歷:
    3. 先遍歷u的輕(非重)兒子,并計(jì)算答案,但不保留遍歷后對(duì)cnt數(shù)組的影響(消除遞歸產(chǎn)生的影響)
    4. 遍歷重兒子,保留對(duì)cnt的影響(不消除遞歸的影響)
    5. 再遍歷u的輕兒子的子樹節(jié)點(diǎn),加入這些結(jié)點(diǎn)的貢獻(xiàn),得到u的答案

    對(duì)于一個(gè)節(jié)點(diǎn),我們遍歷一次重兒子,兩次非重兒子,最劃算
    為什么不合并第一步和第三步呢,因?yàn)閏nt數(shù)組不能重復(fù)使用,不然空間復(fù)雜度太高,需要O(n)內(nèi)完成
    若一個(gè)節(jié)點(diǎn)u被遍歷了x次,則其重兒子被遍歷x次,輕兒子被遍歷2x次
    這樣的復(fù)雜度是O(nlog n)

    int sz[N],son[N];void dfs1(int x){/* 求解重兒子 */sz[x] = 1;for(int i = head[x]; i; i = e[i].next){int y = e[i].to;dfs1(y); sz[x] += sz[y];if(sz[y] > sz[son[x]]) son[x] = y;} }void Delete(int x){/* 刪除的內(nèi)容 */for(int i = head[x]; i; i = e[i].next) Delete(e[i].to); }void modify(int x,int fa){/* 更新的內(nèi)容 */for(int i = head[x]; i; i = e[i].next) modify(e[i].to,fa); }void ins(int x){/* 插入的內(nèi)容 */for(int i = head[x]; i; i = e[i].next) ins(e[i].to); }void dfs2(int x){/* 求解輕兒子并清空 */for(int i = head[x]; i; i = e[i].next)if(e[i].to != son[x]) dfs2(e[i].to), Delete(e[i].to);/* 求解重兒子并保留 */if(son[x]) dfs2(son[x]);/* 用重兒子更新答案 *//* 枚舉輕兒子更新答案,并加入輕兒子 */for(int i = head[x]; i; i = e[i].next) if(e[i].to != son[x]) modify(e[i].to,x), ins(e[i].to);/* 用所有兒子更新答案 */ }

    證明:

    性質(zhì):一個(gè)節(jié)點(diǎn)到根的路徑上輕邊個(gè)數(shù)不會(huì)超過(guò)logn條
    我們考慮一個(gè)點(diǎn)會(huì)被訪問幾次?
    一個(gè)點(diǎn)被訪問只有兩種情況:

  • 在暴力統(tǒng)計(jì)輕邊的時(shí)候訪問到,次數(shù)<logn
  • 通過(guò)重邊/在遍歷的時(shí)候被訪問到,只有一次
  • 如果統(tǒng)計(jì)一個(gè)點(diǎn)的貢獻(xiàn)的復(fù)雜度為O(1)的話,該算法的復(fù)雜度為O(nlogn)

    應(yīng)用

    可以水一些樹套樹的題,也可以把樹上莫隊(duì)O(n√m)吊打
    例題:
    CF741D Arpa’s letter-marked tree and Mehrdad’s Dokhtar-kosh paths
    CF600E Lomsat gelral
    CF570D Tree Requests
    CF208E Blood Cousins
    CF246E Blood Cousins Return
    CF1009F Dominant Indices
    CF375D Tree and Queries

    總結(jié)

    以上是生活随笔為你收集整理的树上启发式合并的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。