BZOJ 2599

http://www.lydsy.com/JudgeOnline/problem.php?id=2599

就是开一个数组t,t[i]表示权值为i的路径最少边数

点分治,找到树的重心分成若干子树后,

得出一棵子树的所有点到根的路径长度x,到根有a条边,用t[k-x]+a更新答案,

全部查询完后,然后再用所有a更新t[x]

把一棵树的所有子树搞完后再遍历所有子树恢复原来t数组

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<map>
#include<algorithm>
#define FOR(i,s,t) for(register int i=s;i<=t;++i)
using namespace std;
const int M=400011,N=200011,MAX=1000011,inf=1e9;
inline int read(){
    int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}
int n,K,cnt,sum,root,ans;
int t[MAX],last[N],son[N],f[N],dis[N],d[N];
bool vis[N];
struct edge{int to,next,v;}e[M];
inline void insert(int u,int v,int w){
	e[++cnt].to=v;e[cnt].next=last[u];last[u]=cnt;e[cnt].v=w;
	e[++cnt].to=u;e[cnt].next=last[v];last[v]=cnt;e[cnt].v=w;
}
inline void getroot(int x,int fa){
	son[x]=1;f[x]=0;
	for(register int i=last[x];i;i=e[i].next)
		if(e[i].to!=fa&&!vis[e[i].to]){
			getroot(e[i].to,x);
			son[x]+=son[e[i].to];
			f[x]=max(f[x],son[e[i].to]);
		}
	f[x]=max(f[x],sum-son[x]);
	if(f[x]<f[root])root=x;
}
inline void cal(int x,int fa){
	if(dis[x]>K)return;
	ans=min(ans,d[x]+t[K-dis[x]]);
	for(register int i=last[x];i;i=e[i].next)
		if(e[i].to!=fa&&!vis[e[i].to]){
			d[e[i].to]=d[x]+1;
			dis[e[i].to]=dis[x]+e[i].v;
			cal(e[i].to,x);
		}
}
inline void add(int x,int fa,bool flag){
	if(dis[x]>K)return;
	if(flag)t[dis[x]]=min(t[dis[x]],d[x]);
	else t[dis[x]]=inf;
    for(register int i=last[x];i;i=e[i].next)
		if(e[i].to!=fa&&!vis[e[i].to])
			add(e[i].to,x,flag);
}
inline void work(int x){
	vis[x]=1;t[0]=0;
	for(register int i=last[x];i;i=e[i].next)
		if(!vis[e[i].to]){
			d[e[i].to]=1;dis[e[i].to]=e[i].v;
		    cal(e[i].to,0);
			add(e[i].to,0,1);
		}
	for(register int i=last[x];i;i=e[i].next)
		if(!vis[e[i].to])
			add(e[i].to,0,0);
	for(register int i=last[x];i;i=e[i].next)
		if(!vis[e[i].to]){
			root=0;sum=son[e[i].to];
			getroot(e[i].to,0);
			work(root);
		}
}
int u,v,w;
int main(){
	n=read();K=read();
	FOR(i,1,K)t[i]=n;
	FOR(i,2,n){
		u=read(),v=read(),w=read();
		++u;++v;
		insert(u,v,w);
	}
	ans=sum=f[0]=n;
	getroot(1,0);
	work(root);
	ans!=n?printf("%d\n",ans):puts("-1");
	return 0;
}

  

posted @ 2017-12-04 21:35  Stump  阅读(150)  评论(0编辑  收藏  举报