poj1741 Tree(点分治模板题)

Tree
Time Limit: 1000MS   Memory Limit: 30000K
Total Submissions: 28490   Accepted: 9502

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



题解:

点击打开链接

这篇东西点分治讲的很好(可惜那边的代码这题过不去QWQ)


点分治模板题。

用点分治算出经过当前重心的满足条件对数,然后删除每个儿子节点的满足条件去重。

时间复杂度nlog^2n


代码(前面也过不去,大概是清空数组时时间太多了,把数组改小卡过去了):

#include <iostream>  
#include <fstream>  
#include <cstdio>  
#include <cmath>  
#include <map>  
#include <set>  
#include <bitset>  
#include <ctime>  
#include <cstring>  
#include <algorithm>  
#include <stack>  
#include <queue>  
#include <vector>  
#include <list> 
using namespace std; 
int tot,n,m,S,MX,summar,root,ans,vis[10001],e[20001],nexr[20001],head[20001],sim[10001],dis[10001],jia[20001],mxson[10001];
void build(int t,int k,int s){
	tot++;
	e[tot]=k;jia[tot]=s;
	nexr[tot]=head[t];head[t]=tot;
}
void getroot(int x,int fa){
	int i;
	sim[x]=1;mxson[x]=0;
	for(i=head[x];i;i=nexr[i]){
		if(e[i]==fa||vis[e[i]])continue;
		getroot(e[i],x);
		sim[x]+=sim[e[i]];
		mxson[x]=max(mxson[x],sim[e[i]]);
	}
	mxson[x]=max(mxson[x],S-sim[x]);
	if(mxson[x]<MX){
		root=x;
		MX=mxson[x];
	}
}
void getdis(int x,int fa,int dist){
	dis[++summar]=dist;
	int i;
	for(i=head[x];i;i=nexr[i]){
		if(vis[e[i]]||e[i]==fa)continue;
		getdis(e[i],x,dist+jia[i]);
	}
}
int consolate(int x,int len){
	memset(dis,0,sizeof(dis));
	summar=0;
	getdis(x,0,len);
	sort(dis+1,dis+summar+1);
	int l=1,r=summar,sum=0;
	while(l<=r){
		if(dis[l]+dis[r]<=m){
			sum+=r-l;
			l++;
		}
		 else r--;
	}
	return sum;
}
void divide(int x){
	ans+=consolate(x,0);
	vis[x]=1;
	int i;
	for(i=head[x];i;i=nexr[i]){
		if(vis[e[i]])continue;
		ans-=consolate(e[i],jia[i]);
		S=sim[e[i]];root=0;
		MX=n+1;getroot(e[i],0);
		divide(root);
	}
}
int main(){
	int i,t,k,s;
	while(1){
		scanf("%d%d",&n,&m);
		if(n==0&&m==0)return 0;
		tot=0;
		memset(head,0,sizeof(head));
		for(i=1;i<n;i++){
			scanf("%d%d%d",&t,&k,&s);
			build(t,k,s);build(k,t,s);
		}
		S=n;MX=n+1;ans=0;
		memset(vis,0,sizeof(vis));
		getroot(1,0);
		divide(root);
		printf("%d\n",ans);
	}
}

猜你喜欢

转载自blog.csdn.net/qq_41510496/article/details/80946394