【题解】 P5021赛道修建

【题解】P5021 赛道修建

二分加贪心,轻松拿省一(我没有QAQ)

题干有提示:

输出格式:

输出共一行,包含一个整数,表示长度最小的赛道长度的最大值。

注意到没,最小的最大值,还要多明显?

那么我们考虑二分。

直接二分答案,假设我们得到了二分答案\(x\),我们就利用这个答案检查是否可行。考虑这样的一种办法,指定一个点为树的根,先将\(dfs\)放下去,每个\(dfs\)都要尽量将这个节点内所有的赛道合成成满足\(\ge x\),并且贡献一条尽量长的赛道上去。假设有一个\(dfs\)表示自己有多于两条多出来的赛道,它们接起来不能满足条件,那么这个答案非法。

#include<iostream>
#include<cstring>
#include<queue>
#include<cstdlib>
#include<vector>
#include<set>
#include<map>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<bitset>
#include<ctime>

using namespace std;
#define TMP template < class ins >
#define endl '\n'
#define RP(t,a,b) for(register int t=(a),edd=(b);t<=edd;t++)
#define ERP(t,a) for(register int t=head[(a)];t;t=e[t].nx)
#define DRP(t,a,b) for(register int t=(a),edd=(b);t>=edd;t--)
#define more(a,b) (a)=(a)>(b)?(a):(b)
typedef long long ll;
TMP inline ins qr(ins tag) {
    char c=getchar();
    ins x=0;
    int q=0;
    while(c<48||c>57)
        q=c==45?-1:q,c=getchar();
    while(c>=48&&c<=57)
        x=x*10+c-48,c=getchar();
    return q==-1?-x:x;
}
const int maxn=50050;
struct E {
    int to,w,nx;
} e[maxn<<1];
int head[maxn];
ll d[maxn];
int cnt;
inline void add(int fr,int to,int w,bool f) {
    e[++cnt]=(E) {
        to,w,head[fr]
    };
    head[fr]=cnt;
    if(f)
        add(to,fr,w,0);
}
int n,m;
ll ans;
ll cmp;
#define pb insert
multiset<ll> sav[maxn];
#define tor multiset<ll>::iterator

ll dfs(int now,int last) {
    if(ans>=m)
        return 0;
    ERP(t,now) {
        if(e[t].to!=last) {
            ll temp=dfs(e[t].to,now)+e[t].w;
            if(temp>=cmp)
                ans++;
            else
                sav[now].pb(temp);
            if(ans>=m)
                return 0;
        }
    }
    ll ret=0;
    if(sav[now].size()==1)
        return max(0ll,*sav[now].begin());
    while(sav[now].size()) {
        tor b=sav[now].begin();
        tor k=sav[now].lower_bound(cmp-(*b));
        if(k==sav[now].end()) {
            more(ret,*b);
            sav[now].erase(b);
            continue;
        }
        if(k==b)
            k++;
        if(k==sav[now].end()) {
            more(ret,*b);
            sav[now].erase(b);
            continue;
        }
        ans++;
        if(ans>=m)
            return 0;
        if(k==b)
            sav[now].erase(k);
        else {
            sav[now].erase(k);
            sav[now].erase(b);
        }
    }
    return ret;
}

inline bool chek(int x) {
    RP(t,1,n)
    sav[t].clear();
    cmp=x;
    ans=0;
    dfs(1,0);
    return ans>=m;
}


inline int eff(int rb) {
    int lb=1,mid;
    do {
        mid=(lb+rb)>>1;
        //cout<<rb<<' '<<mid<<' '<<lb<<endl;
        if(chek(mid))
            lb=mid+1;
        else
            rb=mid-1;
    } while(lb<=rb);
    return rb;
}



void predfs(int now,int last,int w) {
    d[now]=d[last]+w;
    ERP(t,now)
    if(e[t].to!=last)
        predfs(e[t].to,now,e[t].w);
}
int t1,t2,t3;
const int inf=0x3f3f3f3f;
inline void init() {
    n=qr(1);
    m=qr(1);
    RP(t,1,n-1) {
        t1=qr(1);
        t2=qr(1);
        t3=qr(1);
        add(t1,t2,t3,1);
    }
    predfs(1,0,0);
    ll sav=0,rem=-inf;
    RP(t,1,n)
    if(d[t]>rem)
        sav=t,rem=d[t];
    predfs(sav,0,0);
    sav=0,rem=-inf;
    RP(t,1,n)
    if(d[t]>rem)
        sav=t,rem=d[t];
    cout<<eff(rem)<<endl;
}



signed main() {
#ifndef ONLINE_JUDGE
    freopen("testdata.in","r",stdin);
    freopen("out.out","w",stdout);
#endif
    init();
    return 0;
}

posted @ 2019-01-29 20:12  谁是鸽王  阅读(226)  评论(2编辑  收藏  举报