poj1741

这是点分治的入门题。

#include<iostream>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<cstdio>  
using namespace std;
int const N=1e4+10; 
int sz[N],n,k;  
struct edge{
	int to,nt,w; 
}e[N<<1]; 
int cnt,h[N],ans,vis[N],d[N],son,dd[N];  
void add(int a,int b,int c){
	e[++cnt].to=b; 
	e[cnt].w=c; 
	e[cnt].nt=h[a];  
	h[a]=cnt; 
}
int dfs(int x,int fa,int dist){
	int res=1;d[++d[0]]=dist; 
	for(int i=h[x];i;i=e[i].nt){
		int v=e[i].to;  
		if(v==fa || vis[v]) continue; 
		res+=dfs(v,x,dist+e[i].w);  
	}
	return res; 
} 
void find(int x,int fa,int sum){
	sz[x]=1;  
	int mx=0;  
	for(int i=h[x];i;i=e[i].nt){
		int v=e[i].to; 
		if(v==fa || vis[v]) continue;  
		find(v,x,sum);  
		mx=max(mx,sz[v]);  
		sz[x]+=sz[v]; 
	}
	mx=max(mx,sum-sz[x]); 
	if(mx<=sum/2) son=x; 
}
void solve(int x){
	dd[0]=0;  
	for(int i=h[x];i;i=e[i].nt){
		int v=e[i].to;  
		if(vis[v]) continue;  
		d[0]=0;  
		dfs(v,x,e[i].w);  
		sort(d+1,d+d[0]+1);  
		for(int j=1;j<=d[0];j++)  
			if(d[j]<=k) ans++;  
		int q=d[0]; 
		for(int j=1;j<=d[0];j++) {
			while (j<q && d[j]+d[q]>k) q--; 
			if(q>j) ans-=(q-j);  
		}
		for(int j=1;j<=d[0];j++)  
			dd[++dd[0]]=d[j];  
	}
	sort(dd+1,dd+dd[0]+1);  
	int q=dd[0];
	for(int i=1;i<=dd[0];i++){
		while (i<q && dd[i]+dd[q]>k) q--;  
		if(q>i) ans+=(q-i); 
	}
	for(int i=h[x];i;i=e[i].nt){
		int v=e[i].to;  
		if(vis[v]) continue; 
		int s=dfs(v,x,e[i].w);  
		find(v,x,s);  
		vis[son]=1;  
		solve(son); 
	}
}
int main(){
	while (scanf("%d%d",&n,&k)==2){
		if(n==0 && k==0)  
			break; 
		cnt=0; 
		memset(h,0,sizeof(h)); 
		memset(vis,0,sizeof(vis)); 
		for(int i=1;i<n;i++){
			int x,y,z;  
			scanf("%d%d%d",&x,&y,&z); 
			add(x,y,z); 
			add(y,x,z); 
		}
		ans=0; 
		int s=dfs(1,1,0);  
		find(1,1,s);
		vis[son]=1; 
		solve(son);  
		printf("%d\n",ans); 
	}
	return 0; 
}
```c++
posted @ 2020-08-18 20:41  zjxxcn  阅读(89)  评论(0编辑  收藏  举报