1. 程式人生 > >二分+Kruskal【p2798】爆彈虐場

二分+Kruskal【p2798】爆彈虐場

Description

某年某月某日,Kiana 結識了一名爆彈虐場的少年。

Kiana 仗著自己多學了幾年OI,所以還可以勉勉強強給這位少年 講一些自己擅長的題。具體來說,Kiana 先給這位少年灌輸了n 個毫不相干的知識點,然後再通過自己的[資料刪除]技術把這些知識點強行聯絡在一起。

由於這位少年有著爆彈虐場的實力,所以對於每個Kiana 準備強行構造的聯絡,他都能夠自己想出來,不過會花費更多的時間。具體來說,Kiana 一共有m 個聯絡,每個聯絡可以把兩個不相干的知識點連在一起,如果由Kiana 直接來講第i 個聯絡,需要花費ti 的時間, 而如果由少年自己想出來,則需要花費Ti 的時間。

為了偷懶,Kiana 只需要自己講的或少年想出來的聯絡能剛好把知識點全部直接或間接串在一起就可以了。但為了保證教學質量, Kiana 覺得至少有k 個聯絡需要少年自己想出來。由於Kiana 耐心有限,她希望無論是自己講或是少年自己想,構造的聯絡中花費時間最長的一個用時最短。

現在Kiana 想知道,滿足這些條件的情況下,構造的聯絡中耗時最長的一個的最短用時是多少。由於她不會算,所以希望由你告訴她。

Input

輸入檔案包括m+1 行。

第一行包含三個正整數n,k 和m,分別表示知識點的數量,Kiana 希望少年自己想出來的聯絡的數量和聯絡的總數量。

接下來m 行,每行包含四個正整數a,b,Ti 和ti,表示在知識點a 和b 之間可以構造出一個聯絡,這個聯絡由少年自己想出來需要花費 Ti 的時間,而Kiana 直接講出來需要花費ti 的時間。

Output

輸出檔案包括一行。

第一行包含一個正整數,表示構造的聯絡中耗時最長的一個的最短用時。

時間最長用時最短?

顯然二分.

又因為最後要求連通即可,因此最後一定是一個最小生成樹,

所以二分時間,跑\(Kruskal\)建樹即可.

程式碼

#include<cstdio>
#include<cctype>
#define N 500008
#define R register
using namespace std;
inline void in(int &x)
{
    int f=1;x=0;char s=getchar();
    while(!isdigit(s)){if(s=='-')f=-1;s=getchar();}
    while(isdigit(s)){x=x*10+s-'0';s=getchar();}
    x*=f;
}
int n,k,m,l,r=1e7,f[N],ans;
struct cod{int u,v,w;}edge[N],e[N];
int find(int x){return f[x]==x?x:f[x]=find(f[x]);}
inline bool ok(int x)
{
    R int cnt=0;
    for(R int i=1;i<=n;i++)f[i]=i;
    for(R int i=1;i<=m;i++)
    {
        R int u=edge[i].u,v=edge[i].v,w=edge[i].w;
        if(w>x)continue;
        R int fu=find(u),fv=find(v);
        if(fu!=fv)f[fu]=fv;
        cnt++;
    }
    if(cnt<k)return false;
    for(R int i=1;i<=m;i++)
    {
        R int u=e[i].u,v=e[i].v,w=e[i].w;
        if(w>x)continue;
        R int fu=find(u),fv=find(v);
        if(fu==fv)continue;
        f[fu]=fv;
    }
    R int ccc=0;
    for(R int i=1;i<=n;i++)
    {
        if(f[i]==i)
        {
            ccc++;
            if(ccc>1)return false;
        }
    }
    return true;
}
int main()
{
    in(n),in(k),in(m);
    for(R int i=1,a,b,T,t;i<=m;i++)
    {
        in(a),in(b),in(t),in(T);
        edge[i].u=a;edge[i].v=b;edge[i].w=t;
        e[i].u=a;e[i].v=b;e[i].w=T;
    }
    while(l<=r)
    {
        int mid=(l+r)>>1;
        if(ok(mid))r=mid-1,ans=mid;
        else l=mid+1;
    }
    printf("%d",ans);
}