POJ1741 Tree,第一次的點分治

2021-07-16 04:54:56 字數 1414 閱讀 2282

time:2016.08.04

author:xiaoyimi

注意:**中遞迴子樹時對子樹大小的計算有誤,雖然可以保證正確性但是會使得求得的子樹重心並不正確,可能會被卡掉

傳送門思路

考慮節點x為根時 an

sx=σ

(i,j

)[i,

j∈x的

不同子樹

上的節點

]+σ(

i,j)

[i,j

∈x的相

同子樹上

的節點]

可以發現,前一項我們可以通過各節點到x的距離直接求出來,具體做法是做一遍dfs,求得節點與x的距離dis,然後將所有dis排序,o(n)求得(這個比較簡單,我就不詳細說了)

但這種方法同時也會把相同子樹上的節點當成點對算進去,這裡面可能有不滿足條件的點對,也會讓後面的點對重複計算,所以要去掉,具體做法是用相同的方法再計算一遍x的各子樹上的∑a

nsi[

i∈x的

子節點]

,用an

sx減去即可

即我們要求的最終答案為to

tx=a

nsx−

∑ans

i[i∈

x的子節

點]後一項實際上就是各個節點的tot,即∑t

oti[

i∈x的

子節點

顯然這是可以遞迴分治求和的

複雜度是神奇的o(

nlog

2n)

注意:

每次尋找完重心後dis都會改變(這裡的dis[i]實際上是i到當前處理的子樹的根的距離)

不要全域性記錄fa

訪問的點打標記blabla

話說點分……慢慢來嘛

**:

#include

#include

#define m 40004

#define ll long long

using namespace std;

intin()

int n,k,tot,g;

ll ans;

int first[m],siz[m],dis[m],mx[m];

bool vis[m];

struct edgee[m<<1];

void add(int z,int x,int y)

; first[x]=tot;

e[++tot]=(edge);

first[y]=tot;

}void dfs(int x,int s,int fa)

void form(int x,int d,int fa)

ll cal(int x,int d)

void solve(int x,int s)

main()

}

poj 1741 Tree 樹的分治

解 文中有,就是把路徑分成經過樹根,和不經過樹根兩類,每次處理經過樹根的,然後剩下的子樹部分可以遞迴處理,如果每次選取樹的重心,那麼可以保證最多遞迴logn層。經過樹根的先排序,然後o n 的複雜度就能算出,那麼每層的複雜度nlogn,最多遞迴logn層,總複雜度nlogn 2 include in...

poj 1741 Tree 樹的分治

求樹上倆結點之間距離小於k的結點對個數 倆個點a,b的公共祖先為c,那麼這倆個點的距離就可以用dis a,c dis b,c 表示,我們可以不斷的處理這樣c,然後計算距離,處理點對,為了使平均效能最好,我們需要找的c為每一棵子樹的重心 需要注意的算點對的時候這種方法成立的條件是倆個點不在同一顆子樹上...

POJ 1741 Tree 樹的分治

題目 題意 給定一棵樹,有n個點和n 1條邊,邊有邊權,給出乙個k,求樹上任意兩點間的最短距離不大於k的個數 思路 看了09年漆子超的 利用分治法,每次找樹的重心,重心即是在當前樹中刪掉此點後,節點數最多的子樹的節點數最小,找到重心後,求其所有子孫到其的距離,然後統計一下兩兩之和不大於k的個數,另外...