传送门:【POJ】1741 Tree
题目分析:点分治第一题!
每次选择树的重心为根将树分治,每次分治加上所有深度和小于等于K的对数(O(N)可求),然后减去重心到儿子的边重叠的对数(在同一棵子树中的对数),再求出子树的根。
不断重复上述操作直到最后,即可求出答案。
论文题。
代码如下:
#include <cstdio> #include <cstring> #include <algorithm> using namespace std ; typedef long long LL ; #define travel( e , H , u ) for ( Edge* e = H[u] ; e ; e = e -> next ) #define rep( i , a , b ) for ( int i = ( a ) ; i < ( b ) ; ++ i ) #define rev( i , a , b ) for ( int i = ( a ) ; i >= ( b ) ; -- i ) #define FOR( i , a , b ) for ( int i = ( a ) ; i <= ( b ) ; ++ i ) #define clr( a , x ) memset ( a , x , sizeof a ) #define cpy( a , x ) memcpy ( a , x , sizeof a ) const int MAXN = 10005 ; const int MAXE = 20005 ; struct Edge { int v , c ; Edge* next ; } E[MAXE] , *H[MAXN] , *edge ; int dep[MAXN] ; int siz[MAXN] ; int num[MAXN] ; int vis[MAXN] ; int tot_size ; int S[MAXN] ; int n , K ; int root ; int top ; int res ; void clear () { edge = E ; clr ( H , 0 ) ; clr ( vis , 0 ) ; num[0] = tot_size = n ; root = 0 ; } void addedge ( int u , int v , int c ) { edge -> v = v ; edge -> c = c ; edge -> next = H[u] ; H[u] = edge ++ ; } void get_root ( int u , int fa = 0 ) {//求树的重心 siz[u] = 1 ; num[u] = 0 ; travel ( e , H , u ) { int v = e -> v ; if ( !vis[v] && v != fa ) { get_root ( v , u ) ; siz[u] += siz[v] ; num[u] = max ( num[u] , siz[v] ) ; } } num[u] = max ( num[u] , tot_size - siz[u] ) ; if ( num[u] < num[root] ) root = u ; } void get_dep ( int u , int fa = 0 ) {//求到根的长度 if ( dep[u] <= K ) S[top ++] = dep[u] ; siz[u] = 1 ; travel ( e , H , u ) { int v = e -> v ; if ( !vis[v] && v != fa ) { dep[v] = dep[u] + e -> c ; get_dep ( v , u ) ; siz[u] += siz[v] ; } } } int get_num ( int u , int len ) {//得到对数 top = 0 ; dep[u] = len ; get_dep ( u ) ; sort ( S , S + top ) ; int l = 0 , r = top - 1 , ans = 0 ; while ( l < r ) { if ( S[l] + S[r] <= K ) { ans += r - l ; ++ l ; } else -- r ; } return ans ; } void dfs ( int u ) {//分治 vis[u] = 1 ; res += get_num ( u , 0 ) ; travel ( e , H , u ) { int v = e -> v ; if ( !vis[v] ) { res -= get_num ( v , e -> c ) ; root = 0 ; tot_size = siz[v] ; get_root ( v ) ; dfs ( root ) ; } } } void solve () { int u , v , c ; clear () ; rep ( i , 1 , n ) { scanf ( "%d%d%d" , &u , &v , &c ) ; addedge ( u , v , c ) ; addedge ( v , u , c ) ; } res = 0 ; get_root ( 1 ) ; dfs ( root ) ; printf ( "%d\n" , res ) ; } int main () { while ( ~scanf ( "%d%d" , &n , &K ) && ( n || K ) ) solve () ; return 0 ; }