$NOIP2018$赛道修建

\(NOIP2018\)赛道修建

树形结构不带树上算法走典型。

\(DFS\),即可,考虑的方向不能脱离树状结构。

即考虑一棵子树中分出的路线一定是独立的,而那些没用的边可以传上去作为备选答案。

再考虑一个贪心,我们每次上传最大的即可。

#include<bits/stdc++.h>
using namespace std;
namespace AE86
{
	const int bufl=1<<15;
	char buf[bufl],*s=buf,*t=buf;
	inline int fetch()
	{
		if(s==t){t=(s=buf)+fread(buf,1,bufl,stdin);if(s==t)return EOF;}
		return*s++;
	}
	inline int read()
	{
		int a=0,b=1,c=fetch();
		while(!isdigit(c)) b^=c=='-',c=fetch();
		while(isdigit(c)) a=a*10+c-48,c=fetch();
		return b?a:-a;
	}
}
const int N=5e4+10;
int n,m,num_edge,Sum,Ans;
int head[N<<1],Dis[N];
struct Edge{int next,to,dis;} edge[N<<1];
inline void Add(int from,int to,int dis)
{
	edge[++num_edge].next=head[from];
	edge[num_edge].dis=dis;
	edge[num_edge].to=to;
	head[from]=num_edge;
}
inline int Dfs(int pos,int fth,int k)
{
	multiset<int> S; S.clear();
	for(int i=head[pos];i;i=edge[i].next)
		if(edge[i].to!=fth)
		{
			int Bac=Dfs(edge[i].to,pos,k)+edge[i].dis;
			if(Bac>=k) Ans++;
			else S.insert(Bac);
		}
	int Max=0;
	while(S.size())
	{
		if(S.size()==1) return max(Max,*S.begin());
		multiset<int>::iterator It=S.lower_bound(k-*S.begin());
		if(It==S.begin()&&S.count(*It)==1) It++;
		if(It==S.end()) Max=max(Max,*S.begin()),S.erase(*S.begin());
		else Ans++,S.erase(It),S.erase(S.begin());
	}
	return Max;
}
inline bool Check(int k)
{
	Ans=0; Dfs(1,0,k);
	if(Ans>=m) return 1;
	else return 0;
}
inline void Dfs_For_Dia(int pos,int fth)
{
	for(int i=head[pos];i;i=edge[i].next)
		if(edge[i].to!=fth)
		{
			Dfs_For_Dia(edge[i].to,pos);
			Sum=max(Sum,Dis[pos]+Dis[edge[i].to]+edge[i].dis);
			Dis[pos]=max(Dis[pos],Dis[edge[i].to]+edge[i].dis);
		}
}
int main(){
#ifndef ONLINE_JUDGE
    freopen("A.in","r",stdin);
#endif
	n=AE86::read(),m=AE86::read();
	for(int i=1,U,V,D;i<n;i++)
		U=AE86::read(),V=AE86::read(),D=AE86::read(),Add(U,V,D),Add(V,U,D);
	Dfs_For_Dia(1,0);int l=0,r=Sum;
	while(l<r)
	{
		int mid=(l+r+1)>>1;
		if(Check(mid)) l=mid;
		else r=mid-1;
	}
	printf("%d\n",l);
}
posted @ 2019-11-14 15:46  风骨傲天  阅读(120)  评论(0编辑  收藏  举报