POJ 1741 Tree 樹分治
阿新 • • 發佈:2018-08-18
pan || string following truct 最小 print seve div
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.
The last test case is followed by two zeros.
Tree
Time Limit: 20 Sec
Memory Limit: 256 MB
題目連接
http://poj.org/problem?id=1741
Description
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.
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.
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
Sample Output
8
HINT
題意
給你一顆樹,問你有多少個對點的距離小於k
題解:
樹分治,可以去看漆子超的論文,講的很詳細
http://wenku.baidu.com/link?url=7KOPn20aLvKK5PqDmuLjIyj4sqZ6CL1H9qP__JSGvX-AWgX7LR6gC-BZ3PTVCP2ojBHxKZcJ5U3csiRjuspqcoFJfswO7JaEIQyKlxwUzBi
代碼
#include<iostream> #include<stdio.h> #include<vector> #include<cstring> #include<algorithm> using namespace std; #define mem(a,b) memset(a,b,sizeof(a)) #define maxn 10005 struct Edge{ int v,w; Edge(){} Edge(int v1,int w1):v(v1),w(w1){} bool operator<(const Edge& other) const { return w < other.w; } }; vector<Edge> e[maxn]; int n,k; int sum,root,ans,cnt; int f[maxn],vis[maxn],son[maxn],d[maxn],deep[maxn]; void init() { root = ans = cnt = 0; for(int i=0;i<maxn;i++) e[i].clear(); mem(vis,0); mem(f,0); mem(son,0); mem(d,0); mem(deep,0); } void getroot(int u,int fa) { son[u]=1;f[u]=0; for(int i=0;i<e[u].size();i++) { int v = e[u][i].v; if(v == fa || vis[v]) continue; getroot(v,u); son[u] += son[v]; f[u] = max(f[u], son[v]); } f[u]=max(f[u],sum-f[u]); //f[u] 最後求得是以u為根的最大子樹的size //當前樹的root 應該是重心 //重心是f[u] 最小的 if(f[u] < f[root]) root=u; } void getdeep(int u,int fa) { deep[++deep[0]] = d[u]; for(int i=0;i<e[u].size();i++) { int v = e[u][i].v, w = e[u][i].w; if(v==fa || vis[v]) continue; d[v] = d[u] + w; getdeep(v,u); } } int cal(int u,int now) { d[u]=now; deep[0]=0; getdeep(u,0); sort(deep+1,deep+deep[0]+1); int t=0,l=1,r=deep[0]; while (l < r) { if(deep[l] + deep[r] <=k) t+= r-l, l++; else r--; } return t; } void solve(int u) { //計算經過樹根u 的 deep[l] + deep[r] <= k //但因為經過樹根u 的配對點(l,r) 可能不用經過u能 <=k,所以應該去除 //所以每次ans應該計算的是兩個不同子樹的節點l,r 使得 deep[l] + deep[r] <= k ans += cal(u,0); vis[u] = 1; for(int i=0;i<e[u].size();i++) { int v = e[u][i].v, w = e[u][i].w; if(vis[v]) continue; ans -= cal(v,w); sum = son[v]; root = 0; getroot(v,root); solve(root); } } int main () { while (scanf("%d %d",&n,&k) != EOF) { if(n==0&&k==0) break; init(); for(int i=1;i<n;i++) { int u,v,w; scanf("%d %d %d",&u,&v,&w); e[u].push_back(Edge(v,w)); e[v].push_back(Edge(u,w)); } sum=n,f[0]=0x3f3f3f3f; getroot(1,0); solve(root); printf("%d\n",ans); } return 0; }
POJ 1741 Tree 樹分治