Live2D

【NOIP2018】赛道修建(正解)

NOIP题目怎么都好长
使用m条各自无边重叠的边覆盖一棵树的一部分
要求最大化这些边的最短长度

考场上高性价比的做法:点我

最大化最短,这种一看就是二分答案啦……

参考上面的高性价比部分分做法,我们可以把可用的边分为两类:

一类是连接到当前子树的根的路径长度\(Dis[u]\)

一类是当前子树中的路径\(ans[u]\)

在一个子树中,我们可以把短的路径尽可能合并成长路径来统计答案

于是只需要两遍二分即可

代码:

#include<bits/stdc++.h>
#define N 50005
using namespace std;

int n,m,u,v,w;

struct Edge
{
	int next,to,dis;
}edge[N<<1];
int cnt=0,head[N];

inline void add_edge(int from,int to,int dis)
{
	edge[++cnt].next=head[from];
	edge[cnt].to=to;
	edge[cnt].dis=dis;
	head[from]=cnt;
}

template<class T>inline void read(T &res)
{
	char c;T flag=1;
	while((c=getchar())<'0'||c>'9')if(c=='-')flag=-1;res=c-'0';
	while((c=getchar())>='0'&&c<='9')res=res*10+c-'0';res*=flag;
}

bool vis[N];
int fa[N],len[N],Dis[N],ans[N];
int cal(int num,int limit)
{
	int p=1,res=0;
	for(register int i=num;i>p;--i)
	{
		if(vis[i]) continue;
		while(p<i&&(len[p]+len[i]<limit||vis[p])) p++;
		if(p<i&&!vis[p]&&len[p]+len[i]>=limit) res++;
		p++;
	}
	return res;
}

void dfs(int u,int limit)
{
	ans[u]=0;
	for(register int i=head[u];i;i=edge[i].next)
	{
		int v=edge[i].to;
		if(v==fa[u]) continue;
		fa[v]=u;
		Dis[v]=edge[i].dis;
		dfs(v,limit);
		ans[u]+=ans[v];
	}
	int num=0;
	for(register int i=head[u];i;i=edge[i].next)
	{
		int v=edge[i].to;
		if(v==fa[u]) continue;
		len[++num]=Dis[v];
	}
	if(num)
	{
		sort(len+1,len+num+1);
		len[0]=0;
		int w=cal(num,limit);
		ans[u]+=w;
		int L=0,R=num,res;
		while(L<=R)
		{
			int Mid=(L+R)>>1;
			vis[Mid]=1;
			if(cal(num,limit)==w) res=Mid,L=Mid+1;
			else R=Mid-1;
			vis[Mid]=0;
		}
		Dis[u]+=len[res];
	}
	if(Dis[u]>=limit) Dis[u]=0,ans[u]++;
}

bool check(int x)
{
//	cout<<"now is checking: "<<x<<endl;
	memset(ans,0,sizeof(ans));
	memset(Dis,0,sizeof(Dis));
	int num=0;
	dfs(1,x);
	if(ans[1]>=m) return true;
	return false;
}

int main()
{
	int l=1,r=0;
	read(n);read(m);
	for(register int i=1;i<=n-1;++i)
	{
		read(u);read(v);read(w);
		add_edge(u,v,w);
		add_edge(v,u,w);
		r+=w;
	}
	int ans;
	while(l<=r)
	{
		int mid=(l+r)>>1;
		if(check(mid)) ans=mid,l=mid+1;
		else r=mid-1;
	}
	printf("%d\n",ans);
	return 0;
}
posted @ 2019-11-04 21:32  tqr06  阅读(158)  评论(0编辑  收藏  举报