• 【题解】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
  • 相关阅读:
    A. Ivan the Fool and the Probability Theory
    关于消除“输出中最后的一个空格”问题
    半文件式输入中一种常见的输入方式
    持续输入问题
    汉诺塔问题
    给定两个正整数,求它们的最大公约数。
    第三届全国高校绿色计算机大赛(初赛题目)
    第三届全国高校绿色计算机大赛(初赛题目)
    C++中的输入及其原理简析
    流感传染
  • 原文地址:https://www.cnblogs.com/gengyf/p/11633648.html
Copyright © 2020-2023  润新知