POJ 1741 Tree 樹的分治 點分治

2021-06-26 06:40:03 字數 1470 閱讀 7213

題目大意:給出一顆無根樹和每條邊的權值,求出樹上兩個點之間距離<=k的點的對數。

思路:樹的點分治。利用遞迴和求樹的重心來解決這類問題。因為滿足題意的點對一共只有兩種:

1.在以該節點的子樹中且不經過該節點。

2.路徑經過該節點。

對於第一種點,我們遞迴處理;第二種點,我們可以將所有子樹的節點到這個子樹的根節點的距離處理出來,然後排序處理出滿足要求的點對的個數。

按照正常的樹的結構來分割子樹,這樣的做法的時間複雜度肯定是不好看的,為了讓子樹大小盡量相同,我們每次處理這個子樹前找到這個子樹的重心,把這個重心當為根,然後在分割子樹,這樣時間複雜度最壞會降到o(nlog^2n)。

code:

#include #include #include #include #define max 20010

#define inf 0x3f3f3f3f

using namespace std;

int points,edges,k;

int head[max],total;

int next[max << 1],aim[max << 1],length[max << 1];

int cnt[max],c; //每個子樹中經過根節點的滿足條件的對數

int size[max],_size,dis[max],p;

int _total;

bool v[max];

inline void initialize();

inline void add(int x,int y,int len);

void work(int x);

void getroot(int x,int last);

inline int count(int x,int len);

void getdis(int x,int last,int len);

int main()

work(1);

int ans = 0;

for(int i = 1;i <= points; ++i)

ans += cnt[i];

printf("%d\n",ans);

} return 0;

}inline void initialize()

inline void add(int x,int y,int len)

void work(int x)

}void getroot(int x,int last)

max_size = max(max_size,_total - size[x]);

if(max_size < _size)

_size = max_size,c = x;

}inline int count(int x,int len)

return re;

}void getdis(int x,int last,int len)

}

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的個數,另外...