NOIP2018 P5021 賽道修建

2021-10-08 19:58:05 字數 1390 閱讀 8674

看到題意描述第一反應就是先二分那個修建的 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 ...