【题解】Luogu P5021 赛道修建 贪心+二分

①最小值最大->二分答案

②贪心策略

从下向上匹配,先考虑树只有两层(一个根和一堆儿子) 显然想让他们中多出现赛道,我们把边权排序,从最小的边开始,用mid-w得到x,然后找比x略大或等于x的边,因为要使向上匹配的贡献最大,所以不能找比x长太多的边

处理完最下层后向上递归的同时将处理完的链的贡献向上传递

记f[i]为点i从下向上能走到的最长链长度,也就是向上的贡献

每次匹配成功即赛道数--,是否可行直接判断赛道数≤0

code

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 namespace gengyf{
 4 #define ll long long
 5 const int mod=1e9+7;
 6 const int maxn=1e5+10;
 7 inline int read(){
 8     int x=0,f=1;
 9     char c=getchar();
10     while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
11     while(c>='0'&&c<='9'){x=(x*10)+c-'0';c=getchar();}
12     return x*f;
13 }
14 int n,m,q[maxn],f[maxn],ans;
15 struct edge{
16     int to,nxt,w;
17 }e[maxn*2];
18 int head[maxn],cnt,sum,rt,tmp;
19 int v[maxn];
20 inline void add(int from,int to,int w){
21     e[++cnt].to=to;e[cnt].w=w;e[cnt].nxt=head[from];head[from]=cnt;
22 }
23 void dfs(int x,int from,int lim){
24     for(int i=head[x];i;i=e[i].nxt){
25         if(e[i].to!=from){
26             dfs(e[i].to,x,lim);
27         }
28     }
29     int tail=0;
30     for(int i=head[x];i;i=e[i].nxt){
31         if(e[i].to!=from){
32             q[++tail]=f[e[i].to]+e[i].w;
33         }
34     }
35     sort(q+1,q+1+tail);
36     for(int i=tail;i>=1&&q[i]>=lim;i--){
37         tail--;tmp--;
38     }
39     for(int i=1;i<=tail;i++){
40         if(v[i]!=x){
41             int l=i+1,r=tail,res=tail+1;
42             while(l<=r){
43                 int mid=(l+r)>>1;
44                 if(q[i]+q[mid]>=lim){
45                     res=mid;r=mid-1;
46                 }
47                 else l=mid+1;
48             }
49             while(v[res]==x&&res<=tail)res++;
50             if(res<=tail){
51                 v[i]=v[res]=x;tmp--;
52             }
53         }
54     }
55     f[x]=0;
56     for(int i=tail;i>=1;i--){
57         if(v[i]!=x){
58             f[x]=q[i];break;
59         }
60     }
61     return ;
62 }
63 int main(){
64     n=read();m=read();
65     for(int i=1;i<n;i++){
66         int u,v,w;
67         u=read();v=read();w=read();
68         add(u,v,w);add(v,u,w);sum+=w;
69     }
70     rt=1;
71     int l=1,r=sum,mid;
72     while(l<=r){
73         mid=(l+r)>>1;
74         tmp=m;
75         memset(v,0,sizeof(v));
76         dfs(1,0,mid);
77         if(tmp<=0){
78             l=mid+1;ans=mid;
79         }
80         else r=mid-1;
81     }
82     printf("%d",ans);
83     return 0;
84 }
85 }
86 signed main(){
87   gengyf::main();
88   return 0;
89 }
View Code

 

posted @ 2019-10-08 09:25  喵の耳  阅读(110)  评论(0编辑  收藏  举报