noip2018day1 賽道修建

2022-05-20 11:52:07 字數 3501 閱讀 3418

\(c\) 城將要舉辦一系列的賽車比賽。在比賽前,需要在城內修建 $m $條賽道。

\(c\) 城一共有 \(n\) 個路口,這些路口編號為 \(1,2,…,n\)有 $n-1 $條適合於修建賽道的雙向通行的道路,每條道路連線著兩個路口。其中,第 $i $條道路連線的兩個路口編號為 \(a_i\) 和 \(b_i\),該道路的長度為 \(l_i\)。借助這 \(n-1\) 條道路,從任何乙個路口出發都能到達其他所有的路口。

一條賽道是一組互不相同的道路 \(e_1,e_2,…,e_k\),滿足可以從某個路口出發,依次經過 道路 \(e_1,e_2,…,e_k\)(每條道路經過一次,不允許調頭)到達另乙個路口。一條賽道的長度等於經過的各道路的長度之和。為保證安全,要求每條道路至多被一條賽道經過。

目前賽道修建的方案尚未確定。你的任務是設計一種賽道修建的方案,使得修建的 \(m\)條賽道中長度最小的賽道長度最大(即 \(m\) 條賽道中最短賽道的長度盡可能大)

輸入檔案第一行包含兩個由空格分隔的正整數 \(n,m\),分別表示路口數及需要修建的 賽道數。

接下來 \(n-1\) 行,第 \(i\)行包含三個正整數 \(a_i,b_i,l_i\),表示第 \(i\) 條適合於修建賽道的道 路連線的兩個路口編號及道路長度。

保證任意兩個路口均可通過這 \(n-1\) 條道路相互到達。

每行中相鄰兩數之間均由乙個空格分隔。

對於所有的資料, \(2 ≤ n ≤ 50,000\), \(1 ≤ m ≤ n-1\), \(1 ≤ a_i,b_i ≤ n\), \(1 ≤ l_i ≤ 10,000\)。

輸出共一行,包含乙個整數,表示長度最小的賽道長度的最大值。

7 1 

1 2 10

1 3 5

2 4 9

2 5 8

3 6 6

3 7 7

9 3

1 2 6

2 3 3

3 4 5

4 5 10

6 2 4

7 2 9

8 4 7

9 4 4

31

15

很自然的想到是二分。。。

話說為什麼聯賽有那麼多二分???

最小值最大,標準的二分詢問。

我們可以去二分它的最小值最大的答案,然後去\(check\)它。

怎麼去\(check\)它呢?首先,我們先分析路徑的狀態。

一條路徑在樹上有兩種狀態:

掛在乙個節點下面的一條鏈。

兩條掛在節點下的鏈組成的路徑。

很顯然,我們需要一種方法使得所有路徑長度大於等於當前\(x\)的數量最大。

我們可以發現,若以乙個節點為根節點的子樹有殘留的形如\(1\)的鏈有兩種選擇。

將其和其他的鏈進行配對形成如同\(2\)所說的鏈對。

不滿足條件\(1\),將其作為子鏈的一部分並到其父親節點上。

很顯然,只有這樣才可以保證所有的鏈數量最多。

那麼,我們該如何維護這個過程呢?

利用\(mutilset\)動態的維護這個過程就可以了。

當然,作為一名\(oier\)只寫乙個正解是不太友善的。。。萬一掛了呢?

我們要切分!!!

對於一條鏈,問題變成了有\(n\)個數,將其分為\(m\)個不重疊的區間並且每個區間和最大。

這個問題可以直接二分求解,\(check\)函式如下:

bool check(int x)

return tot>=m;

}

對於菊花圖也還是直接二分。

很顯然,我們可以先將所有的邊按照邊權進行一波排序。

然後,我們開兩個指標分別指向開頭和結尾。

我們再移動指標直到其相遇。

我們可以發現,一條長度已經大於等於當前\(x\)的邊可以直接當一條路徑。

而未到當前長度的邊可以從尾指標向前找到乙個相加可以滿足條件的邊即可。

bool check(int x)
#include using namespace std;

#define ll long long

#define reg register

#define raed read

#define debug(x) cerr<

#define erep(i,g,x) for(int i=(g).head[x]; i; i=(g).nxt[i])

inline int read()

templateinline bool min(t &a, t const&b)

templateinline bool max(t &a, t const&b)

const int n=5e4+5,m=5e4+5,mod=1e9+7;

bool mop1;

int n,m,l,r;

struct link_list

inline void addedgepair(const int a,const int b,const int c)

} g;

struct t3flower

inline void solve(void)

sort(a+1,a+cnt+1);

while(l<=r)

printf("%d\n",ans);

}} pflower;

int deg[n];

struct t3list

return tot>=m;

}void dfs(const int x,const int pre)

}inline void solve(void)

dfs(ha,0);

int ans=0;

while(l<=r)

printf("%d\n",ans);

}} plist;

struct t330

len=0;

while(!v.empty())

}inline void solve(void)

printf("%d\n",ans);

}} p100;

int ma,w;

void find(const int x,const int pre,const int s) }

bool mop2;

inline void _main()

r/=m;

find(1,-1,0),find(w,-1,0),min(r,ma);

if(m==1)printf("%d\n",ma);

else if(flag_flower)pflower.solve();

else if(flag_list)plist.solve();

else p100.solve();}

signed main()

noip2018 luogu5021 賽道修建

c 城將要舉辦一系列的賽車比賽。在比賽前,需要在城內修建mm 條賽道。c 城一共有nn 個路口,這些路口編號為 1,2,n1,2,n,有n 1n 1 條適合於修建賽道的雙向通行的道路,每條道路連線著兩個路口。其中,第ii 條道路連線的兩個路口編號為 a iai 和b ibi 該道路的長度為 l il...

Luogu5021 NOIP2018 賽道修建

luogu5021 noip2018 賽道修建 一棵大小為 n 的樹,邊帶權。選 m 條鏈使得長度和最小的鏈最大。m貪心,二分答案 最小最大?二分 先看部分分 於是可以將兩種做法結合 對於每個節點,往上算貢獻 貪心匹配兩個兒子 至於實現,可以考慮 multiset 也可以排序 二分 時間複雜度 o ...

NOIP2018 賽道修建

noip2018 賽道修建 樹形結構不帶樹上演算法走典型。用 dfs 即可,考慮的方向不能脫離樹狀結構。即考慮一棵子樹中分出的路線一定是獨立的,而那些沒用的邊可以傳上去作為備選答案。再考慮乙個貪心,我們每次上傳最大的即可。includeusing namespace std namespace ae...