NOIP2018 D1T3赛道修建

题目链接:Click here

Solution:

最小值最大,考虑二分一个答案\(k\)

考虑在子树内先匹配,最后传递一个值给自己的父亲(因为每条边只能用一次,所以一颗子树最多传递一个值)

那么我们就可以用一个\(multiset\)来存子树的传递值,然后匹配,将剩下的边传递上去就行了

Code:

#include<bits/stdc++.h>
using namespace std;
const int N=5e4+10;
int n,m,cnt,num,l=1,r,u,head[N];
struct Edge{int nxt,to,val;}edge[N<<1];
void ins(int x,int y,int z){
    edge[++cnt].nxt=head[x];
    edge[cnt].to=y;edge[cnt].val=z;
    head[x]=cnt;
}
void dfs(int x,int fa,int dis){
    if(dis>r) r=dis,u=x;
    for(int i=head[x];i;i=edge[i].nxt)
        if(edge[i].to!=fa) dfs(edge[i].to,x,dis+edge[i].val);
}
multiset<int> q[N];
multiset<int>::iterator it;
int calc(int x,int fa,int k){
    q[x].clear();
    for(int i=head[x];i;i=edge[i].nxt){
        int y=edge[i].to,v=0;
        if(y==fa) continue;
        v=calc(y,x,k)+edge[i].val;
        if(v>=k) ++num;else q[x].insert(v);
    }int maxv=0;
    while(!q[x].empty()){
        if(q[x].size()==1) return max(maxv,*q[x].begin());
        int v=*q[x].begin();
        it=q[x].lower_bound(k-v);
        if(it==q[x].begin()&&q[x].count(*it)==1) ++it;
        if(it==q[x].end()){
            maxv=max(maxv,v);
            q[x].erase(q[x].find(*q[x].begin()));
        }else{++num;
            q[x].erase(q[x].find(*it));
            q[x].erase(q[x].find(v));
        }
    }return maxv;
}
int check(int k){
    num=0;calc(1,0,k);
    return num>=m;
}
int read(){
    int x=0,f=1;char ch=getchar();
    while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
    while(isdigit(ch)){x=x*10+ch-48;ch=getchar();}
    return x*f;
}
int main(){
    n=read(),m=read();
    for(int i=1;i<n;i++){
        int x=read(),y=read(),z=read();
        ins(x,y,z),ins(y,x,z);
    }dfs(1,0,0);dfs(u,0,0);
    while(l<=r){
        int mid=l+r>>1;
        if(check(mid)) l=mid+1;
        else r=mid-1;
    }printf("%d\n",l-1);
    return 0;
}

转载于:https://www.cnblogs.com/NLDQY/p/11433170.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值