樹上點分治 poj 1741
阿新 • • 發佈:2018-02-28
man turn str truct case 分治 lines ssi and
Give a tree with n vertices,each edge has a length(positive integer less than 1001).
Define dist(u,v)=The min distance between node u and v.
Give an integer k,for every pair (u,v) of vertices is called valid if and only if dist(u,v) not exceed k.
Write a program that will count how many pairs which are valid for a given tree.
Input The input contains several test cases. The first line of each test case contains two integers n, k. (n<=10000) The following n-1 lines each contains three integers u,v,l, which means there is an edge between node u and v of length l.
The last test case is followed by two zeros.
Output For each test case output the answer on a single line. Sample Input
Sample Output
Define dist(u,v)=The min distance between node u and v.
Give an integer k,for every pair (u,v) of vertices is called valid if and only if dist(u,v) not exceed k.
Write a program that will count how many pairs which are valid for a given tree.
Input The input contains several test cases. The first line of each test case contains two integers n, k. (n<=10000) The following n-1 lines each contains three integers u,v,l, which means there is an edge between node u and v of length l.
The last test case is followed by two zeros.
Output For each test case output the answer on a single line. Sample Input
5 4 1 2 3 1 3 1 1 4 2 3 5 1 0 0
8
題目分析 : 給定一棵樹,以及樹上邊的關系大小,問你又多少對點的距離是小於等於所給定的 d 的
思路分析 : 樹上點分治的板子題,首先尋找樹的重心,以重心為根結點,尋求所有符合題意要求的點對,但是這樣計算會算出一些不符合題目的點對,在減去即可,此時當遍歷到一個新的結點時,此時的情況又可以當成最初的情況,找重心的時候要註意,對它的子樹來說,總的結點數是小於 n 的!!!
代碼示例 :
const int maxn = 1e4+5; const int inf = 0x3f3f3f3f; #define ll long long int n, m; struct node { int to, cost; node(int _to = 0, int _cost = 0):to(_to), cost(_cost){} }; vector<node>ve[maxn]; int root; int size[maxn], mx[maxn]; // size表示每個結點所連的結點數, mx表示對每個根結點所連的最大結點子樹有多少的結點 int balance; bool done[maxn]; int ans = 0; int numm; // 表示結點總數 void getroot(int x, int fa){ size[x] = 1, mx[x] = 0; for(int i = 0; i < ve[x].size(); i++){ int to = ve[x][i].to; if (to == fa || done[to]) continue; getroot(to, x); size[x] += size[to]; mx[x] = max(mx[x], size[to]); } mx[x] = max(mx[x], numm-size[x]); // 對子樹在尋找子樹的重心的過程中,子樹的總結點數是會變小的 if (mx[x] < balance) {balance = mx[x], root = x;} } int cnt = 0; int dep[maxn]; void dfssize(int x, int fa, int d){ dep[cnt++] = d; for(int i = 0; i < ve[x].size(); i++){ int to = ve[x][i].to; int cost = ve[x][i].cost; if (to == fa || done[to]) continue; dfssize(to, x, d+cost); } } int cal(int x, int d){ cnt = 0; dfssize(x, x, d); sort(dep, dep+cnt); int l = 0, r = cnt-1; int sum = 0; while(l < r){ if (dep[l]+dep[r] <= m){ sum += r-l; l++; } else r--; } //printf("sum = %d \n", sum); //system("pause"); return sum; } void dfs(int x){ done[x] = true; ans += cal(x, 0); for(int i = 0; i < ve[x].size(); i++){ int to = ve[x][i].to; int cost = ve[x][i].cost; if (done[to]) continue; ans -= cal(to, cost); balance = inf; numm = size[to]; // 這裏是重點,因為這個地方一直T,還以為寫的代碼有問題 getroot(to, to); //printf("root = %d\n", root); dfs(root); } } int a, b, w; int main() { while(scanf("%d%d", &n, &m) && n+m){ for(int i = 0; i <= 10000; i++) ve[i].clear(); memset(done, false, sizeof(done)); for(int i = 1; i < n; i++){ scanf("%d%d%d", &a, &b, &w); ve[a].push_back(node(b, w)); ve[b].push_back(node(a, w)); } ans = 0; balance = inf; numm = n; getroot(1, 1); //printf("root = %d\n", root); dfs(root); printf("%d\n", ans); } return 0; }
樹上點分治 poj 1741