赛道修建

Posted 66dzb

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了赛道修建相关的知识,希望对你有一定的参考价值。

[Time Gate]

https://www.luogu.org/problem/P5021

 【解题思路】

首先二分答案,贪心计算对于 mid的最大可能答案,判断它和 m的大小。我们称从一条赛道两端点 LCALCALCA 开始的,到一个端点结束的链为对应赛道的半链,令 fi 为以 iiLCA 的最优半链长度。要求对于 i 所有儿子的 f在保证两两匹配数(两个半链合成一条赛道)最多的同时,向 fi转移尽可能大的值。于是将所有 fff 排序贪心找到最大匹配数,然后,二分找到转移给 fif_ifi? 的值。

【code】

 1 #include <bits/stdc++.h>
 2 #define mid ((l+r)>>1)
 3 #define ll long long
 4 #define maxn 50010
 5 using namespace std;
 6 struct Edge
 7     int to,next,val;
 8     Edge(int a=0,int b=0,int c=0)
 9         to=a,next=b,val=c;
10     
11 l[maxn<<1];
12 int head[maxn],cnt,n,m;
13 vector<int> son[maxn];
14 ll f[maxn];
15 int subans[maxn];
16 void Add(int a,int b,int c)
17     l[++cnt]=Edge(b,head[a],c);
18     head[a]=cnt;
19 
20 int check(int u,int pos,int tot,ll x)
21     int res=0,l=0;
22     for (register int r=tot-1;r;--r)
23         r-=r==pos;
24         while (l<r&&son[u][l]+son[u][r]<x) ++l;
25         l+=l==pos;
26         if (l>=r) break;
27         ++res;++l;
28     
29     return res;
30 
31 void Dfs(int u,int fa,ll x)
32     f[u]=subans[u]=0;
33     son[u].clear();
34     for (register int i=head[u];i;i=l[i].next)
35         int v=l[i].to;
36         if (v==fa) continue;
37         Dfs(v,u,x);
38         f[v]+=l[i].val;
39         if (f[v]>=x) subans[u]++;
40         // 如果已经大于 x 则直接计入答案
41         else son[u].push_back(f[v]);
42     
43     int tot=son[u].size();
44     sort(son[u].begin(),son[u].end());
45     int l=0,r=tot,sub=0,res;
46     for (register int r=tot-1;r;--r)
47         while (l<r&&son[u][l]+son[u][r]<x) ++l;
48         if (l>=r) break;
49         ++sub;++l;
50     
51     subans[u]+=sub;
52     // 贪心找出最大的匹配数(两个半链合成一条赛道)
53     if (sub*2==tot) return;
54     l=0,r=tot-1;
55     while(l<=r)
56         int tem=check(u,mid,tot,x);
57         if (tem==sub) res=mid,l=mid+1;
58         else r=mid-1;
59     
60     // 二分找到满足最大匹配的,可以转移给 f_u 的最大值
61     f[u]=son[u][res];
62 
63 bool check(ll x)
64     int tem=0;
65     Dfs(1,0,x);
66     for (register int i=1;i<=n;++i)
67         tem+=subans[i];
68     return tem>=m;
69 
70 int main()
71     ll l=0,r=0,ans,c;
72     scanf("%d%d",&n,&m);
73     for (register int i=1,a,b;i<n;++i)
74         scanf("%d%d%lld",&a,&b,&c),
75         Add(a,b,c),Add(b,a,c),r+=c;
76     r/=(ll)m;
77     // 在这里二分答案
78     while(l<=r)
79         if (check(mid)) ans=mid,l=mid+1;
80         else r=mid-1;
81     
82     printf("%lld\n",ans);
83     return 0;
84 

 

以上是关于赛道修建的主要内容,如果未能解决你的问题,请参考以下文章

P5021 赛道修建

noip2018luogu5021赛道修建

赛道修建

P5021 赛道修建

赛道修建(树上贪心+multiset)

赛道修建