您的位置:首页 > 其它

poj 1741 Tree(树的分治)

2016-08-01 19:53 387 查看
思路:转自别人的:

将无根树转化成有根树进行观察。满足条件的点对有两种情况:两个点的路径横跨树根,两个点位于同一颗子树中。

如果我们已经知道了此时所有点到根的距离a[i],a[x] + a[y] <= k的(x, y)对数就是结果,这个可以通过排序之后O(n)的复杂度求出。然后根据分治的思想,分别对所有的儿子求一遍即可,但是这会出现重复的——当前情况下两个点位于一颗子树中,那么应该将其减掉(显然这两个点是满足题意的,为什么减掉呢?因为在对子树进行求解的时候,会重新计算)。

在进行分治时,为了避免树退化成一条链而导致时间复杂度变为O(N^2),每次都找树的重心,这样,所有的子树规模就会变的很小了。时间复杂度O(Nlog^2N)。

树的重心的算法可以线性求解。

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<vector>
using namespace std;
const int maxn= 10000+5;
#define inf 1e9
vector<pair<int,int> >e[maxn];
vector<int>dep;
int n,k,res,ans,size,root;
int siz[maxn],d[maxn],vis[maxn],dp[maxn];
void dfs1(int u,int fa) //求重心
{
siz[u]=1;
dp[u]=0;
for(int i = 0;i<e[u].size();i++)
{
int v = e[u][i].first;
if(v==fa || vis[v])
continue;
dfs1(v,u);
siz[u]+=siz[v];
dp[u] = max(dp[u],siz[v]);
}
dp[u]=max(dp[u],size-siz[u]);
if(dp[u] < dp[root])
root = u;
}
void dfs2(int u,int fa)
{
dep.push_back(d[u]);
//siz[u]=1;
for(int i = 0;i<e[u].size();i++)
{
int v = e[u][i].first;
int w = e[u][i].second;
if(v==fa || vis[v])
continue;
d[v]=d[u]+w;
dfs2(v,u);
// siz[u]+=siz[v];
}
}
int cal(int u,int di)
{
dep.clear();
d[u]=di;
dfs2(u,-1);
sort(dep.begin(),dep.end());
int ress = 0;
int l = 0,r=dep.size()-1;
while(l<r)
{
if(dep[l]+dep[r]<=k)
ress+=r-l++;
else
r--;
}
return ress;
}
void dfs(int u)
{
ans+=cal(u,0);
vis[u]=1;
for(int i = 0;i<e[u].size();i++)
{
int v = e[u][i].first;
if(vis[v])
continue;
ans-=cal(v,e[u][i].second);
//dp[0] =
size = siz[v];
root = 0;
//res = 0;
dfs1(v,-1);
//printf("%d\n",root);
dfs(root);
}
}
int main()
{
while(scanf("%d%d",&n,&k)!=EOF && (n+k))
{
for(int i = 0;i<=n;i++)
e[i].clear();
memset(vis,0,sizeof(vis));
for(int i = 1;i<n;i++)
{
int u,v,w;
scanf("%d%d%d",&u,&v,&w);
e[u].push_back(make_pair(v,w));
e[v].push_back(make_pair(u,w));
}
size = n;
dp[0]=inf;
dfs1(1,-1);
ans = 0;
// printf("%d\n",root);
dfs(root);
printf("%d\n",ans);
}
}


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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: