BZOJ 1468: Tree

题目大意:

问树上有多少对点他们的距离小于等于k。

题解:
点分治。

代码:

#include<cstdio>
#include<algorithm>
using namespace std;
long long ans;
int n,k,cnt,root,num,tail,last[1000005],sz[1000005],f[1000005],q[1000005],dis[1000005],vis[1000005];
struct node{
	int to,next,val;
}e[1000005];
void add(int a,int b,int c){
	e[++cnt].to=b;
	e[cnt].next=last[a];
	e[cnt].val=c;
	last[a]=cnt;
}
void getroot(int x,int fa){
	sz[x]=1;
	for (int i=last[x]; i; i=e[i].next){
		int V=e[i].to;
		if (V==fa || vis[V]) continue;
		getroot(V,x);
		sz[x]+=sz[V];
		f[x]=max(f[x],sz[V]);
	}
	f[x]=max(f[x],num-f[x]);
	if (f[root]>f[x]) root=x;
}
void getdis(int x,int fa){
	q[++tail]=dis[x];
	for (int i=last[x]; i; i=e[i].next){
		int V=e[i].to;
		if (V==fa || vis[V]) continue;
		dis[V]=dis[x]+e[i].val;
		getdis(V,x);
	}
}
long long calc(int x,int val){
	tail=0;
	dis[x]=val;
	getdis(x,0);
	long long sum=0;
	int head=1;
	sort(q+1,q+tail+1);
	while (head<tail){
		if (q[head]+q[tail]<=k) {
			sum+=tail-head;
			head++;
		}
		else tail--;
	}
	return sum;
}
void dfs(int x){
	ans+=calc(x,0);
	vis[x]=1;
	for (int i=last[x]; i; i=e[i].next){
		int V=e[i].to;
		if (vis[V]) continue;
		ans-=calc(V,e[i].val);
	}
	for (int i=last[x]; i; i=e[i].next){
		int V=e[i].to;
		if (vis[V]) continue;
		root=0;
		num=sz[V];
		getroot(V,0);
		dfs(root);
	}
}
int main(){
	scanf("%d",&n);
	for (int i=1; i<n; i++){
		int a,b,c;
		scanf("%d%d%d",&a,&b,&c);
		add(a,b,c);
		add(b,a,c);
	}
	scanf("%d",&k);
	num=n;
	root=0;
	f[root]=1e9; 
	getroot(1,0);
	dfs(root);
	printf("%lld
",ans);
	return 0;
}

  

原文地址:https://www.cnblogs.com/silenty/p/8733754.html