【NOIP提高组 Day1 T3】赛道修建

题目

https://www.luogu.org/problemnew/show/P5021

思路

因为部分分给得很足,所以我在考场上先打了一堆部分分,建了5个命名空间。
然后在打二叉树的部分分的时候想到了正解。(写完正解,可惜不够时间调试了,100分溜走)

题目大意:给定一棵带权树,将它的一部分拆成 l a t e x m latex m latexm条链,使得权值最短的链的权值最大。
最小的求最大,当然满足无后效性,所以我们考虑二分答案。
然后我们考虑检验。首先,很容易可以发现答案具有无后效性。换句话说,每个子树在计算出它对答案的贡献之后,就只需要计算出它对父节点的贡献。
这是因为,每一个父节点,它能使用的仅有子树的一条链,而不是整个子树的信息。
故而,我们只需要「可以提供给父节点的那条链」的值更新上去即可。我们用 l a t e x f x latex f_{x} latexfx表达这个上传的值。
并且,对于每棵子树是可以贪心地处理的——如果一棵子树中的一条链可以和另一条链组成一条合法的链,那就没必要把它上传了。
这是因为,如果不上传,一定可以对答案产生1的贡献;如果上传了,仅仅是有可能对答案产生1的贡献。
那么我们对每个子树分别考虑。这就转化为了一个新的问题:
「对于一个长度为 l a t e x n latex n latexn的序列,取出其中尽可能多的数对或数,使得数对的和或数的值大于给定值,并且在有遗留数的情况下使得遗留的数的值最大。」
这个问题要怎么做呢?将它们从小到大排序,那么对于大于给定值的数,单独选取是更优的。
然后处理剩下来的数。用双指针做。
如果右指针的数可以与左指针指的数组成合法数对就把右指针推入栈中,直到没有合法的右指针,就考虑栈中是否为空。
如果不为空就说明存在一个可以和左指针匹配的数,那么就将答案加一,否则左指针就找不到数和它匹配了,那么就用它来更新 l a t e x f x latex f{x} latexfx左指针往右推。一直到序列为空。
然后,对于剩下的数,它们一定都可以组成合法数对——这是因为所有被推入栈中的数,都可以和一个比栈中最小数还要小的数组成合法数对。
那么,我们考虑剩下的数的数量的奇偶性。如果是奇数个,那么就计算答案之后用最大值来更新 l a t e x f x latex f_{x} latexfx
这就做完了。

代码

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
struct ee{
    int v;
    int w;
    int nxt;
}e[50005];
int h[50005],et=0;
int n,m;
inline void add(int u,int v,int w){
    e[++et]=(ee){v,w,h[u]};
    h[u]=et;
}
int MN,rt=0,f[50005],nw;
int st[50005],tp=0,st2[50005],tp2=0;
inline void dfs(int X){
    for(int i=h[X];i;i=e[i].nxt){
        dfs(e[i].v);
    }
    tp=0,tp2=0;
    for(int i=h[X];i;i=e[i].nxt){
        st[++tp]=f[e[i].v]+e[i].w;
    }
    std::sort(st+1,st+1+tp);
    while(tp&&st[tp]>=MN){
        --tp;
        ++rt;
    }
    for(int i=1;i<=tp;++i){
        while(i<tp&&st[i]+st[tp]>=MN){
            st2[++tp2]=st[tp];
            --tp;
        }
        if(tp2){
            --tp2;
            ++rt;
        }else{
            f[X]=st[i];
        }
    } 
    if(tp2&1){
        f[X]=st2[1];
    }
    rt+=(tp2>>1);
} 
inline bool chck(int X){
    std::memset(f,0,sizeof(f));
    MN=X;
    rt=0;
    dfs(1);
    if(rt>=m){
        return 1;
    }else{
        return 0;
    }
}
void init(){
    scanf("%d%d",&n,&m);
    int u,v,w;
    for(int i=1;i<n;++i){
        scanf("%d%d%d",&u,&v,&w);
        if(u>v){
            u^=v^=u^=v;
        }
        add(u,v,w);
    }
    int l=0,r=0x3f3f3f3f,mid,ans=0;
    while(l<=r){
        mid=(l+r)>>1;
        if(chck(mid)){
            l=mid+1;
            ans=mid;
        }else{
            r=mid-1;
        }
    }
    printf("%d\n",ans);
}
int main(){
    init();
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
华为ICT云赛道试题(本科)是一个面向大学生的竞赛题目,旨在考察参赛者在ICT云计算领域的相关知识和实际应用能力。 首先,参赛者需要了解ICT云计算的基本概念和背景。ICT云计算是一种通过网络提供计算资源和服务的模式,包括基础设施即服务(IaaS)、平台即服务(PaaS)和软件即服务(SaaS)。它可以提供弹性的计算能力、高可靠性和安全性,为企业和个人提供方便的计算资源。 其次,参赛者需要具备一定的技术知识和编程能力。他们需要了解云计算相关的技术,如虚拟化技术、容器化技术和分布式计算等。此外,他们需要掌握至少一种编程语言,并具有开发和调试程序的能力。 在参加华为ICT云赛道试题时,参赛者需要根据试题的要求进行相应的实践和解答。试题可能包括以下内容: 1. 云计算架构:参赛者需要了解云计算的体系结构,包括物理层、虚拟化层、管理层和服务层。他们需要根据试题要求设计和实现云计算架构。 2. 高可用性和负载均衡:参赛者需要了解实现高可用性和负载均衡的方法,如冗余备份、故障转移和分布式负载均衡等。他们需要根据试题要求设计和实现相关的解决方案。 3. 安全性和隐私保护:参赛者需要了解云计算的安全性和隐私保护问题,包括身份认证、数据加密和访问控制等。他们需要根据试题要求设计和实现相应的安全策略。 4. 大数据分析:参赛者需要了解大数据分析的基本原理和方法,包括数据采集、数据清洗和数据建模等。他们需要根据试题要求对给定的数据进行分析和处理。 综上所述,华为ICT云赛道试题(本科)是一个考察参赛者在ICT云计算领域知识和实践能力的竞赛题目。参赛者需要具备相关的技术知识和编程能力,并根据试题要求进行相应的实践和解答。这不仅可以提高参赛者的专业技能,还有助于推动ICT云计算的发展和应用。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值