poj1741Tree 点分治

  上午学习了点分治,写了1个半小时终于写出一个代码--poj1741,可以说是个模板题。

  分治:对于每个儿子找出重心,分别处理

  注意:1.每次处理一个重心后,ans减去对它儿子的处理 

      原因:因为统计方法没管是否在同一棵树上,所以答案有重复

     2.每次寻找新的重心时,树的大小变化,重新计算大小,否则TLE

CODE:

#include<cstdio>
#include<iostream>
#include<cstring>
#include<vector>
#include<algorithm>
#include<cmath>
#define ll long long
#define inf 2147483647
#define N 10005
using namespace std;
int n,k,dis[N],f[N],siz[N],vis[N],rt,ans,size;
struct node{
	int v,w;
};
vector<int>d;
vector<node>g[N];


void getrt(int u,int fa){
	siz[u]=1;f[u]=0;
	for(int i=0;i<g[u].size();i++){
		int v=g[u][i].v;
		if(vis[v]||v==fa)continue;
		getrt(v,u);
		siz[u]+=siz[v];
		f[u]=max(f[u],siz[v]);
	}
	f[u]=max(f[u],size-siz[u]);
	if(f[u]<f[rt])rt=u;
}


void getdis(int u,int fa){
	d.push_back(dis[u]);
	for(int i=0;i<g[u].size();i++){
		int v=g[u][i].v,w=g[u][i].w;
		if(vis[v]||v==fa)continue;
		dis[v]=dis[u]+w;
		getdis(v,u);
	}
}

int cal(int u,int fir){
	int ret=0;
	d.clear();
	dis[u]=fir;
	getdis(u,0);
	int l=0,r=d.size()-1;
	sort(d.begin(),d.end());
	while(l<r){
		while(d[l]+d[r]>k&&l<r)r--;
		ret+=r-l;l++;
	}
	return ret;
	
}

void work(int u){
	ans+=cal(u,0);
	vis[u]=1;
	for(int i=0;i<g[u].size();i++){
		int v=g[u][i].v,w=g[u][i].w;
		if(vis[v])continue;
		ans-=cal(v,w);
		f[0]=size=siz[u];
		getrt(v,rt=0);
		work(rt);
	}
}

int main(){
	while(1){
		scanf("%d%d",&n,&k);
		if(!n)break;
		for(int i=1;i<=n;i++)
		g[i].clear(),vis[i]=0;
		int u,v,w;
		for(int i=1;i<n;i++)
		scanf("%d%d%d",&u,&v,&w),
		g[v].push_back(node{u,w}),
		g[u].push_back(node{v,w});
		ans=0;f[0]=size=n;
		getrt(1,rt=0);
		work(rt);
		printf("%d
",ans);
	}
	return 0;
}

  

原文地址:https://www.cnblogs.com/wsy01/p/6782137.html