點分治

Rose_Lu發表於2024-04-01

最近學了點分治,覺得挺厲害的,準備寫一下加深印象。
樹上的東西都很抽象,所以自然要用抽象的東西來做,就比如點分治,點分治的思路是在當前的子樹中找重心,然後用重心做事情,為什麼用重心,因為重心可以使得複雜度降到log級別,然後再在這個子樹裡找你要的東西就行了,因為是每次都會用子樹做,所以複雜度是O(nlogn)
以例題為例。
【P3806 【模板】點分治 1 】
題意:找樹上距離為k的數
考慮點分治,對於每一個子樹,記錄它到重心的距離,然後在找距離的過程中去看每次詢問的距離有沒有相等的,如果有就記錄下來,最後輸出就好

  • 找重心
    根據定義直接找對於當前點所有的子樹中最大的子樹節點數最少的就行了。
void zzx(int x, int fa) {
    sz[x] = 1, maxs[x] = 0;
  // sz是當前點的兒子(包含自己)的大小,maxs是它的最大的兒子
    for(int i = head[x]; i; i = e[i].nxt) {
        int to = e[i].to;
        if(fa == to || vis[to]) continue;
		zzx(to, x);
		sz[x] += sz[to];
		maxs[x] = max(maxs[x], sz[to]);
	}
	maxs[x] = max(maxs[x], S - sz[x]);
  //可能反著來他的兒子會更大,所以要加一下這個判斷
	if(maxs[x] < maxs[root]) root = x;
  //按照定義找重心
}

別的就按題意寫就行

相關文章