[NOIP2018 Day1 T3]赛道修建 Solution

本文探讨了一种在树形结构中寻找互不相交链的问题,通过二分查找与贪心算法结合,确定了在给定数量条件下,链中最短链的最大可能长度。采用特定的数据结构和算法优化,如multiset和DFS,实现了高效求解。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题意:给一棵树,现在要从上面划出mmm条互不相交的链(指边不能共用),问这些链中长度最短的最长可以达到多少。
最短最长没什么好说的了,考虑二分。
考虑如何判定?
使用贪心。
给每个点都开一个multisetmultisetmultiset,然后将子树拼接后剩下的最长链插入这个点的multisetmultisetmultiset里面,然后从左往右检索该multisetmultisetmultiset,对于每个值二分出第一个值使得它们拼接后大于等于二分的值,然后拼接,最后把剩下的数里面最大的往上传即可。
code:code:code:

#include <bits/stdc++.h>
using std::cin;
using std::cout;
#define regi register int
int n,m;
int head[500001],tot;
std::multiset<int>chain[100001];
std::multiset<int>::iterator left,right;
int Make;
struct edge{
	int to;
	int nxt;
	int w;
}e[1000001];
inline void add(int x,int y,int z){
	e[++tot]={y,head[x],z};
	head[x]=tot;
}
int dfs(int x,int f,int Long){
	chain[x].clear();
	for(regi i=head[x];i;i=e[i].nxt){
		regi y=e[i].to;
		if(y==f)
		  continue;
		regi tmp=dfs(y,x,Long)+e[i].w;
		if(tmp>=Long){
			++Make;
			continue;
		}
	  chain[x].insert(tmp);
	}
	int max=0;
  for(left=chain[x].begin();left!=chain[x].end();++left){
    right=chain[x].lower_bound(std::max(Long-*left,*left+1));
    if(right!=chain[x].end()&&*left+*right>=Long){
    	chain[x].erase(right); 
    	++Make;
    }
    else
      if(left!=--chain[x].end()&&*left*2>=Long){
      	chain[x].erase(++left);
      	++Make;
      }
    else
      max=std::max(max,*left);
  }
  return max;
}
inline bool check(int x){
	Make=0;
  dfs(1,0,x);
  if(Make>=m)
    return 1;
  return 0;
}
main(){
	std::ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
  cin>>n>>m;
  for(regi i=1,x,y,z;i<n;++i){
  	cin>>x>>y>>z;
  	add(x,y,z);
  	add(y,x,z);
  }
  int l=1,r=0x3f3f3f3f;
  while(l<r){
  	regi mid=l+r+1>>1;
  	if(check(mid))
  	  l=mid;
  	else
  	  r=mid-1;
  }
  cout<<l;
  return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值