樹上啟發式合併

2021-10-10 23:42:57 字數 3901 閱讀 5846

解決樹上統計問題,o(n

∗log

(n))

o(n*log(n))

o(n∗lo

g(n)

),可以結合線段樹等資料結構維護深度上的資訊

部落格

入門題

const

int maxn =

1e5+7;

const

int mod =

1e9+7;

ll n, m, u, v, mx, sum;

vector<

int> mp[maxn]

;int sz[maxn]

, son[maxn]

;void

dfs(

int u,

int fa)

}ll col[maxn]

, cnt[maxn]

, ans[maxn]

, flag;

void

count

(int u,

int fa)

else

if(cnt[col[u]

]== mx)

sum +

= col[u]

;for

(auto v : mp[u])}

void

clear

(int u,

int fa)

}voiddf(

int u,

int fa,

bool kp)

if(son[u]

)count

(u, fa)

; flag =

0, ans[u]

= sum;if(

!kp)

}int

main()

dfs(1,

0);df

(1,0

,1);

for(

int i =

1; i <= n; i++

) cout << ans[i]

<<

" ";

return0;

}

結合線段樹維護深度上的最值

#define mid ((tr[k].l + tr[k].r) >> 1)

#define ls k << 1

#define rs k << 1 | 1

const

int maxn =

1e5+7;

const

int mod =

1e9+7;

int n, t, flag, mxdep;

int sz[maxn]

, son[maxn]

, dep[maxn]

, val[maxn]

;ll sum[maxn]

, ans[maxn]

;vector<

int> mp[maxn]

;void

dfs(

int u,

int dp)

}struct node tr[maxn <<2]

;void

build

(int k,

int l,

int r)

build

(k <<

1, l, mid)

,build

(k <<1|

1, mid +

1, r)

; tr[k]

.w =

max(tr[k <<1]

.w, tr[k <<1|

1].w);

}void

change

(int k,

int pl,

int x)

if(pl <= mid)

change

(k <<

1, pl, x)

;else

change

(k <<1|

1, pl, x)

; tr[k]

.w =

max(tr[k <<1]

.w, tr[k <<1|

1].w);

}ll query()

void

init()

for(

int i =

0; i <= n *

4; i++

) tr[i]

.l = tr[i]

.r = tr[i]

.w =0;

}void

count

(int u)

void

clear

(int u)

voiddf(

int u,

int kep)

if(son[u]

)count

(u);

ans[u]

=query()

;if(!kep)

}int

main()

dfs(1,

1);build(1

,1, mxdep);df

(1,1

);for(

int i =

2; i <= n; i++

) cout << ans[i]

<<

"\n";}

return0;

}

按層維護26個字母的數量

const

int maxn =

5e5+7;

const

int mod =

1e9+7;

int n, q, t, flag, mxdep;

int sz[maxn]

, son[maxn]

, dep[maxn]

, ques[2]

[maxn]

;char val[maxn]

;vector<

int> mp[maxn]

, que[maxn]

;int cnt[maxn][40

];mapint> ans;

void

dfs(

int u,

int dp)

}void

count

(int u)

void

clear

(int u)

bool

check

(int dp)

voiddf(

int u,

int kep)

if(son[u]

)count

(u);

for(

auto d : que[u]

) ans=

check

(d);if(

!kep)

}int

main()

cin >> val +1;

dfs(1,

1);for

(int i =

1, a, b; i <= q; i++)df

(1,1

);for(

int i =

1; i <= q; i++)]

) cout <<

"yes"

<< endl;

else

cout <<

"no"

<< endl;

}return0;

}

樹上啟發式合併

樹上啟發式合併,一種美妙的黑科技,可以用普通的優化讓你 n 2 變成嚴格 n log 解決一些類似 樹上數顏色,樹上查眾數 這樣的問題 首先你要知道暴力為什麼是 n 2 的 以這個圖為例 每次你從乙個節點開始向下搜,你從1節點搜到3,搜完這個子樹然後你需要把3存的col等資訊刪去再遍歷另乙個子樹才是...

樹上啟發式合併總結

某一天發現一道樹上啟發式合併裸題,但我不會寫 學習並刷了兩天的題,是時候來寫個總結了 樹上啟發式合併 dsu on tree 是乙個在o n logn o nlogn o nlog n 時間內解決許多樹上問題的有力演算法。但它的中心其實是 暴力!沒錯,它正是由暴力優化而來。我們先看一道例題 cf60...

dsu on tree 樹上啟發式合併

詳解 dsu on tree 樹上啟發式合併 演算法總結 習題 經典例題 題意 一棵樹有n個結點,每個結點都是一種顏色,每個顏色有乙個編號,求樹中每個子樹的最多的顏色編號的和。dsu on tree簡介 在o n 2 的暴力做法中,我們用cnt記錄每種顏色出現的次數,對於每個結點,遍歷這棵子樹上的所...