Tree(樹分治 點分治)

2021-08-21 20:22:06 字數 1918 閱讀 2401

原題:poj-1741

題意:

有一棵n個節點的樹,每條邊都有乙個權值,問有多少個節點之間的距離小於等於k,

解析:

典型的樹分治,對於每一棵樹,我們首先找到它的重心

重心:一棵樹中以這個點為root時的最大子樹的節點數最小

int siz[n]

,maxn[n]

;//這棵子樹大小,最大子樹大小

void

getg

(int p,

int fa,

int sum)

} maxn[p]

=max

(maxn[p]

,sum-siz[p]);

//當然還要這棵樹的上半部分比較

if(maxn[g]

>maxn[p]

)g=p;

}

然後計算和這個節點有關的題目中要求的東西,然後就可以刪除這個點,變成很多棵樹,在對每棵子樹進行同樣的操作

其他的就看題目寫了

例如:len<=k的計算過程

我們可以快速算出以a點作為中間點或是端點的點對有幾對滿足要求

假設b到a的距離+g到a的距離<=k,那麼在陣列中相應的兩個len即滿足要求,所以轉化為len陣列有幾對<=k,這個只需要排序後用兩個指標遍歷一下就可以了(需要把自己:0加進去)

int

cal(

int p,

int length)

return sum;

}

但是這個時候,假設ad+ae<=k,那麼我們也是算了的,但是其實不存在dbabe,而是dbe,所以再刪除乙個部分即可

\,\\\,

\,\\\,

**:

const

int n =

10009

;int n,k;

int head[n]

,nex[

2*n]

,to[

2*n]

,from[

2*n]

,v[2

*n],now;

void

add(

int a,

int b,

int vv)

int ans;

int g;

int vis[n]

;//是否刪除

int siz[n]

,maxn[n]

;//這棵子樹大小,最大子樹大小

void

getg

(int p,

int fa,

int sum)

} maxn[p]

=max

(maxn[p]

,sum-siz[p]);

//當然還要這棵樹的上半部分比較

if(maxn[g]

>maxn[p]

)g=p;

}int dep[n]

,num,len[n]

;void

dfs(

int p,

int fa)

}int

cal(

int p,

int length)

return sum;

}void

divide

(int p)

}int

main()

}

POJ 1741 Tree 樹的分治 點分治

題目大意 給出一顆無根樹和每條邊的權值,求出樹上兩個點之間距離 k的點的對數。思路 樹的點分治。利用遞迴和求樹的重心來解決這類問題。因為滿足題意的點對一共只有兩種 1.在以該節點的子樹中且不經過該節點。2.路徑經過該節點。對於第一種點,我們遞迴處理 第二種點,我們可以將所有子樹的節點到這個子樹的根節...

點分治(樹分治)

將原問題分解成若干相同形式,相互獨立的子問題,各個擊破 一般用來解決有關樹上路徑的統計和詢問 p4178 tree 給定一棵 n 個節點的樹,每條邊有邊權,求出樹上兩點距離小於等於 k 的點對數量。暴力做法 o n2 點分治做法 選擇乙個點作為分治中心,令其為rt做dfs。對於一條路徑path u,...

1468 Tree 樹的點分治

樓教主男人八題之一 好可怕 似乎不是很難的樣子。點分治大致是這樣 先選出乙個根 一般是重心 然後可以把兩個點之間的路徑分為經過根的和不經過根的,經過根的直接處理記錄,不經過根的遞迴處理計算。似乎還用到了容斥原理的方法。記錄經過當前根的方案數的方法是 先以當前的根為起點遍歷一遍記下di s 陣列即到根...