dsu on tree 樹上啟發式合併

2021-10-11 09:21:20 字數 2305 閱讀 5865

詳解:dsu on tree(樹上啟發式合併)演算法總結+習題

經典例題:

題意:一棵樹有n個結點,每個結點都是一種顏色,每個顏色有乙個編號,求樹中每個子樹的最多的顏色編號的和。

dsu on tree簡介:

在o(n^2)的暴力做法中,我們用cnt記錄每種顏色出現的次數,對於每個結點,遍歷這棵子樹上的所有結點找到答案,然後清空cnt陣列。dsu on tree中,當這個結點是它父親的重兒子時,我們就先找父親其他兒子(輕兒子)的答案,最後遍歷這棵子樹,並保留這顆子樹cnt陣列記錄,那麼我們回溯找父親結點的答案時就不需要再遍歷一遍它的重兒子了。

時間複雜度o(log n):

我們考慮每個結點被統計的次數,那麼從它到跟結點的路徑中,有一條輕邊,就會被統計一次。因為是輕兒子就會被刪除記錄,然後找這個輕兒子的父親結點的答案時,又會被統計一次。而由重鏈剖分可以保證每個結點到跟結點的路徑上輕便不會超過log n條。

#include

#include

using namespace std;

#define ll long long

#define ull unsigned long long

#define pii pair

#define mid ((l + r)>>1)

#define chl (root<<1)

#define chr (root<<1|1)

#define lowbit(x) ( x&(-x) )

const

int manx =

1e5+10;

const

int inf =

2e9;

const

int mod =

1e4+7;

int color[manx]

,hson[manx]

,sz[manx]

;//color每個結點的顏色、hson重兒子

//sz每個子樹的大小

ll cnt[manx]

,maxcnt,sum;

//cnt記錄每種顏色出現次數,maxcnt記錄每種顏色出現次數的最大值,

//sum維護每個結點的答案

ll ans[manx]

;//記錄每個結點的答案

int cou,head[manx]

;struct node

edge[manx<<2]

;void

init

(int n)

sz[0]

=-1;

}void

add1

(int s,

int e)

; head[s]

=cou++;}

void

dfs_list

(int s,

int fa)

//找每個結點重兒子

}void

add(

int f,

int s,

int fa,

int k)

//k為 1時,加上 這棵子樹中每個顏色出現的次數

//k為-1時,減去 這棵子樹中每個顏色出現的次數

//f表示這棵子樹根結點的重兒子(k=1時,不需要遍歷它

for(

int i=head[s]

;~i;i=edge[i]

.bf)

}void

dfs_dot

(int s,

int fa,

int keep)

if(hson[s]

)dfs_dot

(hson[s]

,s,1);

//2、找重兒子的答案,記錄cnt

add(hson[s]

,s,fa,1)

;//3、再遍歷一遍輕兒子,找結點s的答案,記錄cnt

ans[s]

=sum;if(

!keep)

add(

0,s,fa,-1

),sum=maxcnt=0;

//結點s不是重兒子(keep==0)時,清空cnt,刪除記錄

}int

main()

dfs_list(1

,0);

dfs_dot(1

,0,1

);for(

int i=

1;i<=n;i++

)printf

("%lld%c"

,ans[i]

,i==n?

'\n'

:' ');

return0;

}

dsu on tree 樹上啟發式合併

樹上啟發式合併 用於處理離線查詢的子樹問題 第一次先求出重兒子 第二次dfs的過程中,先計算輕兒子,貢獻不保留,再計算重兒子,貢獻保留 最後再加上輕兒子的貢獻,計算出當前節點的值 複雜度為o nlogn 每個節點都有乙個顏色編號 計算一棵以1為根的樹的以每個節點為根的子樹中顏色最多的顏色編號和 這題...

dsu on tree 樹上啟發式合併

對於一顆靜態樹,o nlogn 時間內處理子樹的統計問題。是一種優雅的暴力。很顯然,樸素做法下,對於每顆子樹對其進行統計的時間複雜度是平方級別的。考慮對樹進行乙個重鏈剖分。雖然都基於重鏈剖分,但不同於樹剖,我們維護的不是樹鏈。對於每個節點,我們先處理其輕兒子所在子樹,輕子樹在處理完後消除其影響。然後...

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

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