\(\mathcal {NOIP2018}\) 赛道修建 - 竞赛题解

额……考试的时候大概猜到正解,但是时间不够了,不敢写,就写了骗分QwQ

现在把坑填好了~


题目

(Copy from 洛谷)

题目描述

C 城将要举办一系列的赛车比赛。在比赛前,需要在城内修建 \(m\) 条赛道。

C 城一共有 \(n\) 个路口,这些路口编号为 \(1,2,...,n\),有 \(n-1\) 条适合于修建赛道的双向通行的道路,每条道路连接着两个路口。其中,第 \(i\) 条道路连接的两个路口编号为 \(a_i\) 和 \(b_i\),该道路的长度为 \(l_i\) 。借助这 \(n-1\) 条道路,从任何一个路口出发都能到达其他所有的路口。

一条赛道是一组互不相同的道路 \(e_1,e_2,…,e_k\),满足可以从某个路口出发,依次经过 道路 \(e_1,e_2,…,e_k\)(每条道路经过一次,不允许调头)到达另一个路口。一条赛道的长度等于经过的各道路的长度之和。为保证安全,要求每条道路至多被一条赛道经过。

目前赛道修建的方案尚未确定。你的任务是设计一种赛道修建的方案,使得修建的 \(m\) 条赛道中长度最小的赛道长度最大(即 \(m\) 条赛道中最短赛道的长度尽可能大)

输入输出格式

输入格式:

输入文件第一行包含两个由空格分隔的正整数 \(n,m\),分别表示路口数及需要修建的 赛道数。

接下来 \(n-1\) 行,第 ii 行包含三个正整数 \(a_i,b_i,l_i\) ,表示第 \(i\) 条适合于修建赛道的道 路连接的两个路口编号及道路长度。保证任意两个路口均可通过这 \(n-1\) 条道路相互到达。每行中相邻两数之间均由一个空格分隔。

输出格式:

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


解析

首先题目非常重要——这是一个树形结构,而且满足单调性(即如果答案为x,则>x的值都不能符合条件,<x的值都符合条件)。

那么根据单调性就可以二分了,还是比较容易想到二分答案。然后就是检验的问题了……

如果大家做了“菊花图”(就是从一个顶点伸出去很多条边)的部分数据,就应该知道有一个贪心的性质——对于一个点u,如果连接 u 和 u的一个儿子 的边的长度大于等于答案,那就把这条边割开,单独形成一条路径;接下来考虑长度比答案小的边,那么我们尽量地将长度大的边与较小边匹配形成一条路径。这样的话我们就可以写出来一段代码(AC的):

//edg[]是u与u的儿子的边的长度(都不超过二分出来的答案)
sort(edg,edg+n);
int res=0;
for(int l=0,r=n;l<r;r--){
while(l<r && edg[l]+edg[r]<ans) l++;
if(l>=r) break;
res++; //新构成的路径
l++;
}

我们不妨考虑每一个点 u 及其儿子 v[] ——形成路径的情况无非是①加上u->v[i]的边形成一个路径;②加上u->v[i]和u->v[j]的边形成一个路径;③加上u->v[i]的边然后再与u的祖先相连。

不难想到我们可以把每棵子树都看成一个菊花图做一次贪心。

但是有上述的情况③,这样的话就不能直接看边权了,我们可以让 dp[u] 表示在点u的子树以u为端点的路径的长度。然后考虑子树u中u的一个儿子v,如果 dp[v]+(u->v的边长) 满足答案,就将已经构成的路径个数cnt++;否则将 dp[v]+(u->v的边长) 储存到use[u]中。最后把use[u]中的边按菊花图的方法做一次贪心,就可以得到能够构成的路径条数的最大值:

for(int l=0,r=use[u].size()-1;r>=0;r--){
while(l<r && use[u][l]+use[u][r]<num) l++;
if(l>=r) break;
mat++;l++;
}
fans[u]+=mat; //储存答案

贪心的想,在这里一定要尽可能多的构成路径,但是在这个条件下将尽可能长的一个没必要匹配的路径留下来继续向u的祖先连接;很明显这也是存在单调性的——如果选择一条长度为X的路径“留下来”可以得到最大构成的路径数,那么长度小于X的路径就一定也可以得到最大路径数。

while(l+1<r){
int mid=(l+r)>>1;
if(Check(u,mid,use[u].size(),num)==mat) l=mid;
else r=mid;
}
dp[u]=use[u][l];

这样就可以检验了,即看能够得到的路径条数是否能够满足要求。

(不知道大家看懂没啊……有什么问题的话还是直接在文末的作者邮箱里面问吧QwQ)


源代码

/*Lucky_Glass*/
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=50000;
struct EDGE{
int to,nxt;ll dis;
EDGE(){}
EDGE(int _to,int _nxt,ll _dis):to(_to),nxt(_nxt),dis(_dis){}
}edg[N*2+5];
int adj[N+5],edgtot;
void AddEdge(int u,int v,ll dis){
edg[++edgtot]=EDGE(v,adj[u],dis);
adj[u]=edgtot;
}
int n,m;
vector< int > use[N+5];
int dp[N+5],fans[N+5];
int Check(int u,int tag,int siz,ll num){
int res=0;
for(int l=0,r=siz-1;r;r--){
if(r==tag) r--;
while(l<r && use[u][l]+use[u][r]<num) l++;
if(l==tag) l++;
if(l>=r) break;
res++;l++;
}
return res;
}
void DFS(int u,int pre,ll num){
dp[u]=fans[u]=0;use[u].clear();
for(int i=adj[u];i;i=edg[i].nxt){
int v=edg[i].to;ll dis=edg[i].dis;
if(v==pre) continue;
DFS(v,u,num);
dp[v]+=dis;
if(dp[v]>=num) fans[u]++;
else use[u].push_back(dp[v]);
}
sort(use[u].begin(),use[u].end());
int mat=0;
for(int l=0,r=use[u].size()-1;r>=0;r--){
while(l<r && use[u][l]+use[u][r]<num) l++;
if(l>=r) break;
mat++;l++;
}
fans[u]+=mat;
if(mat*2==use[u].size()) return;
int l=0,r=use[u].size();
while(l+1<r){
int mid=(l+r)>>1;
if(Check(u,mid,use[u].size(),num)==mat) l=mid;
else r=mid;
}
dp[u]=use[u][l];
}
bool Check(ll num){
DFS(1,-1,num);
int res=0;
for(int i=1;i<=n;i++)
res+=fans[i];
return res>=m;
}
int main(){
scanf("%d%d",&n,&m);
ll l=0,r=0;
for(int i=1;i<n;i++){
int u,v;ll dis;scanf("%d%d%lld",&u,&v,&dis);
AddEdge(u,v,dis);AddEdge(v,u,dis);
r+=dis;
}
r/=1ll*m;
while(l+1<r){
ll mid=(l+r)>>1;
if(Check(mid)) l=mid;
else r=mid;
}
if(Check(r)) printf("%lld\n",r);
else printf("%lld\n",l);
return 0;
}

\(\mathcal{THE\ END}\)

\(\mathcal{Thanks\ for\ reading!}\)

\(\mathcal{email:\ lucky\_glass@foxmail.com}\ 尽量在平时回答一下问题QwQ\)

竞赛题解 - NOIP2018 赛道修建的更多相关文章

  1. 【LG5021】[NOIP2018]赛道修建

    [LG5021][NOIP2018]赛道修建 题面 洛谷 题解 NOIP之前做过增强版还没做出来\(QAQ\) 一看到题目中的最大值最小,就很容易想到二分答案 重点是考虑如何\(check\) 设\( ...

  2. Luogu5021 [NOIP2018]赛道修建

    Luogu5021 [NOIP2018]赛道修建 一棵大小为 \(n\) 的树,边带权.选 \(m\) 条链使得长度和最小的链最大. \(m<n\leq5\times10^4\) 贪心,二分答案 ...

  3. 竞赛题解 - NOIP2018 保卫王国

    \(\mathcal{NOIP2018}\) 保卫王国 - 竞赛题解 按某一个炒鸡dalao名曰 taotao 的话说: \(\ \ \ \ \ \ \ \ \ "一道sb倍增题" ...

  4. 竞赛题解 - NOIP2018 旅行

    \(\mathcal {NOIP2018} 旅行 - 竞赛题解\) 坑还得一层一层的填 填到Day2T1了 洛谷 P5022 题目 (以下copy自洛谷,有删减/修改 (●ˇ∀ˇ●)) 题目描述 小 ...

  5. 【题解】NOIP2018 赛道修建

    题目戳我 \(\text{Solution:}\) 根据题目信息简化题意,是让你在树上找出\(m\)条路径使得路径长度最小值最大. 看到题第一感先二分一个答案,问题转化为如何选择一些路径使得它们最小值 ...

  6. [NOIP2018]赛道修建(二分+multiset)

    考场上打了一个 \(vector\) 解法,因为我当时不会 \(multiset\) 好吧,我来讲一讲今年的 \(tgD1T3\) 首先,这题 \(55\) 分是不难想的 1. \(b_i=a_i+1 ...

  7. 【比赛】NOIP2018 赛道修建

    最小值最大,二分长度 然后判断赛道大于等于这个长度最多可以有多少条 可以贪心,对于一个点和它的一些儿子,儿子与儿子之间尽量多配(排序后一大一小),剩下的选个最长的留给自己的父亲就好了 具体实现可以用一 ...

  8. [NOIP2018]赛道修建

    嘟嘟嘟 因为一些知道的人所知道的,不知道的人所不知道的原因,我来改写今年的NOIP了. 现在看这题,心中满是疑问:我当时是多么的zz,这种水题为啥没做出来-- 不管了,说正事. 先考虑部分分. 1.\ ...

  9. luogu5021 [NOIp2018]赛道修建 (二分答案+dp(贪心?))

    首先二分一下答案,就变成了找长度>=m的 不相交的路径的个数 考虑到在一个子树中,只有一个点能出这个子树去和别的点搞 所以我这个子树里尽量自我满足是不会有坏处的 而且要在自我满足数最大的条件下, ...

随机推荐

  1. 第9课 备忘便签-TinyDB

    编写一只个性化的App便签小程序,TinyDB可能会帮上你.   1.组件设计 1)TextBox1输入需要记录存储的信息记录 2)四只button分别作为“添加 编辑 删除清空”信息记录 3)Lli ...

  2. python(day1-11)

    day1:Python入门 day2:数字类型字符编码 day3:函数 day4:模块与包 day5:常用模块 day6:面向对象 day8:异常处理 day9:网络编程 day10:并发编程 day ...

  3. wpf 转型 android开发总结

    今年马上就要过去了,这一年中我经历了从wpf转型到qt/qml,然后最近又要开始搞android,从我个人的经验来看不论是qml还是android从框架和设计上都跟wpf类似,并且移动端的设计因为很多 ...

  4. QML Delegate中访问该持有者的方式 附加属性(转载)

    http://blog.csdn.net/yuxiaohen/article/details/17226971   用法很奇葩记录一下,实测可以,用于弱化delegate与持有者的依赖 delegat ...

  5. SQL Server ->> PARSE函数

    这个函数和TRY_PARSE一起从SQL Server 2012引入.它的存在是因为TRY_PARSE一旦遇到无法成功转换就会以NULL值返回,而如果你希望以报错的形式,你就可以用PARSE. 比如 ...

  6. Android笔记——Socket通信实现简单聊天室

    两部分,客户端和服务端 ---------------------------------------------------------------- 客户端  1.为防止ANR异常,互联网连接可用 ...

  7. 【Leetcode】【Medium】Divide Two Integers

    Divide two integers without using multiplication, division and mod operator. If it is overflow, retu ...

  8. RESTful架构及SOA架构简单解析

    1.RESTful架构 本人也是刚接触ASP.NET开发,以下为自己简单的理解,并做了一些记录,表述不当或者错误之处还请指正,在此谢过. 首先,REST(REpresentational State  ...

  9. vim的visual模式

    在可视化模式下,可以对一个文本块的整体进行操作.例如,首先高亮选中一部分文本,然后用d命令删除这个文本块.可视化模式的好处在于,你可以在做改动之前,就看到操作将影响的文本.可视化模式可以分为以下三种: ...

  10. Ubuntu双系统安装过程中遇到的问题

    1.在第六步选择时区的时候,会报错,这时候可以选择断开网络(取消右上角的网络选项)! 2.用easybcd添加启动项以后,无法进入,F12进入BIOS,选择Ubuntu进入,因为以前的BIOS BOO ...