Tree
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. 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 Sample Output 8 Source
LouTiancheng@POJ
|
[Submit] [Go Back] [Status] [Discuss
题意,是给出一个树,要求距离小于k的结点对数,树的点分冶。
由容质原理,一棵树的结点对数为
没有限制的 - ∑端点落在同一颗子树上的. 上述两个过程是一样的, 于是只考虑没有限制的怎么做。所以用树的点分冶,统计经过树根的个数,然后,分别统计经过,每个结点的个数,反正,对于一棵树,不论以谁看成是根结点,都是可以的。那么,找那个结点作为根最好呢,当然是树的重心。
1.求树的重心,就是有个结点,以它为根的话,它所有的子树的最大结点最小,用树形dp的做法,可以在o(n)复杂度内解决。
dp[i]表示,以i为根,子树的结点数的最大值。则dp[i] = max(dp[j],总结点数 - nodes[i]);j是i的子树,nodes[i]表示i为根,所有的结点数。以i为根的时候,还要考虑到我们是以i的根搜下来的,所以要用总是减去i为根的总结点数,就是以i的父结点为i子结点时的总个数。
2.统计以i为根没有限制的对数,我们把所以的i的树上的结点到i的距离,用一个深搜统计起来,再加入一个数组,排下序,转化成了,要在一个排了序的数组a1 a2 .... an 求出ai + a[j] <=k(j > i)的个数,这里,就可以用o(n)方法统计出来。枚举每个i,因为a[i]是递增的,所以j就是递减的。由于j只会减不会增,所以,是线性算法。端点落在同一颗子树上的和没有限制的是同一个问题,只要以子结点为根统计,就可以了。
总的说一下,由于每次是以重心为根,那么子结点的个数一定就是减少了一半的,所以在log(n)可以解决,对于一棵树,由于,每个树都要统计排序,复杂度为n * log(n),所以总的复杂度为o(n * log(n) * log(n));也就可以过了。
#define N 10050 #define M 100005 #define maxn 205 #define MOD 1000000000000000007 int n,m,k,u,v,l,center,all,num,nodes[N],dp[N],dep[N]; ll ans; bool vis[N]; vector<pii> p[N]; vector<int> depV; void findRoot(int root,int fa){ nodes[root] = 1;dp[root] = 0; FI(p[root].size()){ int g = p[root][i].first; if(g != fa && !vis[g]){ findRoot(g,root); nodes[root] += nodes[g]; dp[root] = max(dp[root],nodes[g]); } } dp[root] = max(dp[root],all - nodes[root]); if(dp[root] < num){ num = dp[root];center = root; } } int getRoot(int root,int sn){ num = INF;all = sn;center = root; findRoot(root,-1); return center; } void getDp(int root,int fa){ nodes[root] = 1; depV.push_back(dep[root]); FI(p[root].size()){ int g = p[root][i].first; if(g != fa && !vis[g]){ dep[g] = dep[root] + p[root][i].second; getDp(g,root); nodes[root] += nodes[g]; } } } ll cal(int root,bool isfirst){ depV.clear(); if(isfirst) dep[root] = 0; getDp(root,-1); sort(depV.begin(),depV.end()); ll sum = 0; for(int i = 0,j = depV.size() - 1;i < depV.size();i++){ while(j>i && depV[i] + depV[j] > k) j--; if(j > i) sum += (ll)(j - i); } return sum; } int work(int root,int fa){ vis[root] = true; ans += cal(root,true); FI(p[root].size()){ int g = p[root][i].first; if(g != fa && !vis[g]){ ans -= cal(g,false); work(getRoot(g,nodes[g]),-1); } } } int main() { while(S2(n,k)!=EOF && n + k) { ans = 0; FI(n) p[i + 1].clear(),vis[i + 1] = false; FI(n-1){ S2(u,v);S(l); p[u].push_back(mp(v,l)); p[v].push_back(mp(u,l)); } work(getRoot(1,n),-1); printf("%lld\n",ans); } return 0; }
Home Page Go Back To top