记录编号 223070 评测结果 AAAAAAAAAA
题目名称 [POJ1741][男人八题]树上的点对 最终得分 100
用户昵称 Gravatarmikumikumi 是否通过 通过
代码语言 C++ 运行时间 0.771 s
提交时间 2016-02-06 23:21:25 内存使用 0.59 MiB
显示代码纯文本
#include<cstdio>
#include<vector>
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cmath>
using namespace std;
const int SIZEN=10020;
vector<pair<int,int> > s[SIZEN];
int N,K,root;
bool vis[SIZEN];
int siz[SIZEN],pos[SIZEN];
int cnt;//当前子树的大小
bool read()
{
	scanf("%d%d",&N,&K);
	if(N==0&&K==0) return 0;
	int u,v,l;
	memset(vis,0,sizeof(vis));
	for(int i=1;i<=N;i++) s[i].clear();
	for(int i=1;i<N;i++)
	{
		scanf("%d%d%d",&u,&v,&l);
		s[u].push_back(make_pair(v,l));
		s[v].push_back(make_pair(u,l));
	}
	return 1;
}
void getroot(int x,int fa)//寻找树的重心
{
	pos[x]=0,siz[x]=1;
	for(int i=0;i<s[x].size();i++)
	{
		int v=s[x][i].first;
		if(v==fa||vis[v]) continue;
		getroot(v,x);
		siz[x]+=siz[v];
		pos[x]=max(pos[x],siz[v]);
	}
	pos[x]=max(cnt-siz[x],pos[x]);
	if(!root||pos[x]<pos[root]) root=x;
}
int tot;
int dep[SIZEN],dis[SIZEN];
void getdep(int x,int fa)//得到x到其子树内部各点的距离
{
	//为了减少之后排序的时间复杂度,在这里使用了dep
	dep[tot++]=dis[x];
	for(int i=0;i<s[x].size();i++)
	{
		int v=s[x][i].first;
		if(v==fa||vis[v]) continue;
		dis[v]=dis[x]+s[x][i].second;
		getdep(v,x);
	}
}
int clac(int x,int lo)
{
	dis[x]=lo;
	tot=0;
	getdep(x,0);
	sort(dep,dep+tot);
	int ans=0,r=tot-1,l=0;
	while(l<r)
	{
		while(r>l&&dep[r]+dep[l]>K) r--;
		ans+=r-l;
		l++;
	}
	return ans;
}
int TC(int x)//将以x为根的子树分治
{
	int ans=0;
	vis[x]=1;
	ans+=clac(x,0);
	for(int i=0;i<s[x].size();i++)
	{
		int v=s[x][i].first;
		if(!vis[v])
		{
			ans-=clac(v,s[x][i].second);
			root=0;cnt=siz[v];getroot(v,0);
			ans+=TC(root);
		}
	}
	//cout<<x<<" "<<ans<<endl;
	return ans;
}
void work()
{
	root=0;cnt=N;getroot(1,0);
	printf("%d\n",TC(root));
}
int main()
{
	freopen("poj1741_tree.in","r",stdin);
	freopen("poj1741_tree.out","w",stdout);
	while(read())
	{
		work();
	}
	return 0;
}