题解 [NOIP2018 提高组] 赛道修建
挺综合的一道题目。
询问最小值最大,考虑二分最小值,二分上下界是 ,但是为了方便我们直接设为 即可。
考虑如何 ,可以采用类似树形 的方式进行贪心。对于节点 的子树, 内部的点显然可以构成几条链,同时我们也可以从 内部引一条链出去,和上面的节点进行搭配,从而使得边权和大于我们二分的值。
问题也就转化为:将 的儿子尽可能的凑合,凑合出最多的链数量,然后从没有凑合好的链中选出一条最长的传上去,也就是说:在保证节点 内部的链数量最多,使得上传的权值最大。
对于节点 的儿子传上来的权值 ,若 ,则直接计入贡献即可;反之先放到一边。
对于刚才不符合条件的 ,进行处理:由于要保证最终剩下来的最大,且一对搭配的贡献始终是 ,所以我们从小开始,查找与之搭配符合条件的,并选上,最终剩下的就是最大的。返回到父亲节点即可。
#include<bits/stdc++.h> using namespace std; typedef long long LL; const int N=5e4+10; int n,m; struct node { int to,w; }; vector<node> g[N]; void add(int x,int y,int z) { g[x].push_back({y,z}); } int sum=0; LL dfs(int nd,int fa,LL s) { multiset<LL> st,st2; multiset<LL>::iterator it; for(node t:g[nd]) { int x=t.to,w=t.w; if(x==fa) continue; LL res=dfs(x,nd,s)+(LL)w; if(res>=s) sum++; else st.insert(res); } LL maxn=0; while(st.size()>=2) { LL minn=*st.begin(); st.erase(st.begin()); it=st.lower_bound(s-minn); if(it==st.end()) { maxn=max(maxn,minn); continue; } sum++; st.erase(it); } if(st.size()) return max(maxn,*(--st.end())); else return maxn; } int check(LL s) { sum=0; dfs(1,0,s); if(sum>=m) return 1; else return 0; } int main() { cin>>n>>m; for(int i=1;i<n;i++) { int a,b,l; cin>>a>>b>>l; add(a,b,l); add(b,a,l); } LL l=1,r=500000000; while(l<r) { LL mid=(l+r+(LL)1)/2; if(check(mid)) l=mid; else r=mid-1; } cout<<l; return 0; }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
· 为什么 退出登录 或 修改密码 无法使 token 失效