1. 程式人生 > >【noip2018】【luogu5021】賽道修建

【noip2018】【luogu5021】賽道修建

 

題目描述

C 城將要舉辦一系列的賽車比賽。在比賽前,需要在城內修建 mm 條賽道。

C 城一共有 nn 個路口,這些路口編號為 1,2,…,n1,2,,n,有 n-1n1 條適合於修建賽道的雙向通行的道路,每條道路連線著兩個路口。其中,第 ii 條道路連線的兩個路口編號為 a_iai  b_ibi,該道路的長度為 l_ili。藉助這 n-1n1 條道路,從任何一個路口出發都能到達其他所有的路口。

一條賽道是一組互不相同的道路 

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

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

輸入輸出格式

輸入格式:

 

輸入檔案第一行包含兩個由空格分隔的正整數 n,mn,

m,分別表示路口數及需要修建的 賽道數。

接下來 n-1n1 行,第 ii 行包含三個正整數 a_i,b_i,l_iai,bi,li,表示第 ii 條適合於修建賽道的道 路連線的兩個路口編號及道路長度。保證任意兩個路口均可通過這 n-1n1 條道路相互到達。每行中相鄰兩數之間均由一個空格分隔。

 

輸出格式:

 

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

 

輸入輸出樣例

輸入樣例#1:   複製
7 1 
1 2 10 
1 3 5 
2 4 9 
2 5 8 
3 6 6 
3 7 7
輸入樣例#2:   複製
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
輸出樣例#2:   複製
15

 

輸出樣例#1:   複製
31

 

 

 

 

 

 

 

 

【資料規模與約定】

對於所有的資料, 2 ≤ n ≤ 50,0002n50,000 1 ≤ m ≤ n-11mn1 1 ≤ a_i,b_i ≤ n1ai,bin 1 ≤ l_i ≤ 10,0001li10,000

題解:

       題意即求一個k段不相交路徑長度最小值的最大值;

       二分這個最大的最小值mid,那麼要求判斷是否有一種方案可以分出>=k條路徑使得權值都>=mid;

      樹形dp  : 當做到節點u,要麼u的所有兒子都一定成為了路徑,要麼至多有一條可以向上延伸的路徑;

      這樣如果可以在u形成>=mid的路徑,那麼一定比此時不形成路徑往上連更優;

      記錄每個點可以往上連的權值val,考慮u的兒子v,u,v之間的邊為E[i]  (程式碼風格,忍受一下。。)

      val[v]+E[i].w >= mid 直接統計為一條合法路徑;

      否則把左邊存在一個數組裡,可以知道要形成路徑只能兩兩配對,排序後二分可以確定最大的對數;

      注意未配對的最大的數可能可以替換已配對的權值,找到最大可替換數設定成val[u](注意細節)

      複雜度   $O(n log^2 n)$

 

 

 1 #include<cstdio>
 2 #include<iostream>
 3 #include<vector>
 4 #include<algorithm>
 5 #define inf 0x3f3f3f3f
 6 #define rg register 
 7 #define il inline 
 8 #define Run(i,l,r) for(int i=l;i<=r;i++)
 9 using namespace std;
10 const int N=50500;
11 int n,k,o,hd[N],mid,val[N],sum,p[N];
12 vector<int>g[N];
13 struct Edge{int v,nt,w;}E[N<<1];
14 void adde(int u,int v,int w){
15     E[o]=(Edge){v,hd[u],w};hd[u]=o++;
16     E[o]=(Edge){u,hd[v],w};hd[v]=o++; 
17 }
18 bool check2(int u,int Mid){
19     int cnt=g[u].size();
20     int p=cnt-(Mid<<1); 
21     for(int i=1;i<=Mid;i++){
22         if(g[u][p+i-1]+g[u][cnt-i]<mid)return false;
23     }
24     return true;
25 }
26 void dfs(int u,int fa){
27     g[u].clear();
28     val[u]=0;
29     for(int i=hd[u];i;i=E[i].nt){
30         int v=E[i].v;
31         if(v==fa)continue;
32         dfs(v,u);
33         int t=E[i].w+val[v];
34         if(t>=mid)sum++;
35         else g[u].push_back(t); 
36     }
37     int cnt=(int)g[u].size();
38     if(!cnt)return;
39     sort(g[u].begin(),g[u].end());
40     int l=0,r=cnt>>1;
41     while(l<r){
42         int Mid=(l+r+1)>>1;
43         if(check2(u,Mid))l=Mid;
44         else r=Mid-1;
45     }
46     sum+=l;
47     if((l<<1)==cnt)return;
48     for(int i=0;i<l;i++){
49         int t1=cnt-(l<<1)+i;
50         int t2=cnt-1-i;
51         p[t1]=t2;
52         p[t2]=t1;
53     }
54     int t;
55     for(t=cnt-(l<<