列表

详情


NC21468. [NOIP2018]赛道修建

描述

C城将要举办一系列的赛车比赛。在比赛前,需要在城内修建𝑚条赛道。
C城一共有𝑛个路口,这些路口编号为1,2,…,𝑛,有𝑛−1条适合于修建赛道的双向通行的道路,每条道路连接着两个路口。其中,第𝑖条道路连接的两个路口编号为𝑎_𝑖𝑏_𝑖,该道路的长度为𝑙_𝑖。借助这𝑛−1条道路,从任何一个路口出发都能到达其他所有的路口。
一条赛道是一组互不相同的道路满足可以从某个路口出发,依次经过道路(每条道路经过一次,不允许调头)到达另一个路口。一条赛道的长度等于经过的各道路的长度之和。为保证安全,要求每条道路至多被一条赛道经过。
目前赛道修建的方案尚未确定。你的任务是设计一种赛道修建的方案,使得修建的𝑚条赛道中长度最小的赛道长度最大(即𝑚条赛道中最短赛道的长度尽可能大)。

输入描述

输入文件第一行包含两个由空格分隔的正整数𝑛,𝑚,分别表示路口数及需要修建的赛道数。
接下来𝑛−1行,第𝑖行包含三个正整数表示第𝑖条适合于修建赛道的道路连接的两个路口编号及道路长度。保证任意两个路口均可通过这𝑛−1条道路相互到达。每行中相邻两数之间均由一个空格分隔。

输出描述

输出共一行,包含一个整数,表示长度最小的赛道长度的最大值。

示例1

输入:

7 1
1 2 10
1 3 5
2 4 9
2 5 8
3 6 6
3 7 7

输出:

31

原站题解

上次编辑到这里,代码来自缓存 点击恢复默认模板

C++14(g++5.4) 解法, 执行用时: 226ms, 内存消耗: 13260K, 提交时间: 2019-09-14 17:46:09

#include<bits/stdc++.h>
using namespace std;
int n, m;
vector<vector<pair<int, int>>> G;

int dfs(int s, int f, int l, int &tot) {
  vector<int> tmp;
  for (auto it: G[s]) if (it.first != f) {
    tmp.push_back(it.second + dfs(it.first, s, l, tot));
  }
  if (tmp.size() == 0) return 0;
  int t = *max_element(tmp.begin(), tmp.end()); 
  if (t < (l + 1)/2) return t;
  //delete it or need -O2

  sort(tmp.begin(), tmp.end());
  multiset<int> S;
  for (auto t: tmp) {
    if (t >= l) tot++;
    else if (S.lower_bound(l-t) != S.end()) tot++, S.erase(S.lower_bound(l-t));
    else S.insert(t);
  }
  return S.empty()?0: *prev(S.end()); 
}

int main() {
  ios_base::sync_with_stdio(false);
  cin >> n >> m;
  G.resize(n + 1);
  int s = 0;
  for (int i = 0; i < n - 1; i++) {
    int a, b, l; cin >> a >> b >> l;
    G[a].push_back({b, l});
    G[b].push_back({a, l});
    s += l;
  }
  int lo = 0, hi = s / m + 1;
  while (lo < hi) {
    int mid = (lo + hi) / 2;
    int tot = 0;
    dfs(1, -1, mid, tot);
    if (tot < m) hi = mid;
    else lo = mid + 1;
  }
  cout << hi - 1 << endl;
}

C++11(clang++ 3.9) 解法, 执行用时: 504ms, 内存消耗: 7188K, 提交时间: 2020-08-15 21:49:59

#include<bits/stdc++.h>
using namespace std;
const int N=2e5+5;
int n,m,K,ans;
int hd[N],nxt[N],to[N],w[N],tot;
void add(int a,int b,int c)
{
	to[++tot]=b,w[tot]=c,nxt[tot]=hd[a],hd[a]=tot;
}
int dfs(int u,int f)
{
	multiset<int> st;
	for(int i=hd[u];i;i=nxt[i])
	{
		if(to[i]!=f) st.insert(dfs(to[i],u)+w[i]);
	}
	multiset<int>::iterator p1,p2;
	while((p1=st.end())!=st.begin()&&*--p1>=K)
	{
		++ans;
		st.erase(p1);
	}
	int re=0;
	while((p1=st.begin())!=st.end())
	{
		int tmp=*p1;
		st.erase(p1);
		if((p2=st.lower_bound(K-tmp))!=st.end())
		{
			++ans;
			st.erase(p2);
		}
		else re=tmp;
	}
	return re;
}
bool check()
{
	ans=0;
	dfs(1,0);
	return ans>=m;
}
int main()
{
	scanf("%d%d",&n,&m);
	for(int i=1,x,y,z;i<n;++i)
	{
		scanf("%d%d%d",&x,&y,&z);
		add(x,y,z);
		add(y,x,z);
	}
	int L=0,R=5e8;
	while(L<R)
	{
		K=L+R+1>>1;
		if(check()) L=K;
		else R=K-1;
	}
	printf("%d\n",L);
}

上一题