看到題意描述第一反應就是先二分那個修建的 mm 條賽道中長度最小的賽道的長度 k ,然後 o(n)o(n) 或 o(n\log n)o(nlogn) 判斷。
那麼怎麼判斷呢?
對於每個結點,把所有傳上來的值 valval 放進乙個 multisetmultiset ,其實這些值對答案有貢獻就兩種情況:
val≥k
val_a+val_b≥k
那麼第一種情況可以不用放進 multiset,直接答案 +1 就好了。第二種情況就可以對於每乙個最小的元素,在 multiset中找到第乙個+val_b≥k 的數,將兩個數同時刪去,最後把剩下最大的值傳到那個結點的父親
因此這道題本質上是樹的dfs和二分答案的結合。主要注意的是每個結點的子節點計算val_a+val_b≥k時,val_b盡量小,因而使用lower_bound
#include #include #include #include #include #include #include using namespace std;
const int maxn = 50010;
struct node
a[maxn << 1];
int n, m, head[maxn], tot = 0, ans, up;
multisetsetson[maxn];
inline int read()
while (c >= '0'&&c <= '9')
return x*y;
}void add(int x, int y, int w)
int getl(int x, int fa)
up = max(up, sum1 + sum2);
return sum1;
}int dfs(int x, int fa, int mid)
}multiset::iterator it;
int max = 0;
while (!setson[x].empty())
it = setson[x].lower_bound(mid - *setson[x].begin());
if (it == setson[x].begin() && setson[x].count(*it) == 1) it++;
if (it != setson[x].end())
else if (it == setson[x].end())
} return max;
}bool check(int mid)
int main()
getl(1, 0);
int l = 1, r = up, mid;
while (l < r)
} cout << l;
return 0;
}
P5021 賽道修建 NOIP2018
傳送門 考場上把暴力都打滿了,結果檔案輸入輸出寫錯了.當時時間很充裕,如果認真想想正解是可以想出來的.問你 長度最小的賽道長度的最大值 顯然二分答案 考慮如何判斷是否可行 顯然對於乙個節點,它最多只能向父親傳一條路徑長度 那麼其它路徑的合併只能在子樹間進行 貪心一波,如果一段路徑在子樹就可以合併出合...
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 ...