P5021 賽道修建 NOIP2018

2022-05-19 11:45:14 字數 1492 閱讀 8088

傳送門

考場上把暴力都打滿了,結果檔案輸入輸出寫錯了....

當時時間很充裕,如果認真想想正解是可以想出來的..

問你 長度最小的賽道長度的最大值

顯然二分答案

考慮如何判斷是否可行

顯然對於乙個節點,它最多只能向父親傳一條路徑長度

那麼其它路徑的合併只能在子樹間進行

貪心一波,如果一段路徑在子樹就可以合併出合法長度

那麼直接合併一定是不會比傳給父親再考慮合併更劣的

子樹都合併完後,剩下的肯定傳最長的長度給父親

考慮在子樹內如何貪心地進行最優合併

顯然最小的邊去找最小的能使它合法的邊合併

(注意不是最大的邊去找最小的能使它合法的邊合併)

那麼用乙個multiset存一下當前節點的各個邊長

然後就按前面的方法乙個個合併就好了

注意和並時的一些細節和二分的上界,(因為multiset常數大,所以要把上界設為總長除賽道數)

#include#include

#include

#include

#include

#include

using

namespace

std;

typedef

long

long

ll;const

int n=1e5+7,inf=2e9+7

;inline

intread()

while(ch>='

0'&&ch<='

9')

return x*f;

}int fir[n],from[n<<1],to[n<<1],val[n<<1

],cntt;

inline

void add(int &a,int &b,int &c)

intn,m,mid,cnt;

intf[n];

multiset

s;multiset

::iterator it,itt,pit;

void dfs(int x,int

fa) s.clear();

//記得清空

for(int i=fir[x];i;i=from

[i])

it=s.begin();

while(it!=s.end())

f[x]=0;/*

記得先清空f

*/ it=s.begin(); if(s.end()!=it) it=s.end(),it--,f[x]=*it;//

注意必須有邊傳才更新f

}inline

intjudge()

intmain()

int l=0,r=s/m;

while(r-l>1

)

mid=r;

printf("%d

",judge() ?r : l);

return0;

}

洛谷P5021 賽道修建

話說去年為什麼暴力炸成了15.其實我現在都不會做,參考的一位p黨大佬的題解,寫成了c 版而已 附註了一些關鍵部分的細節 總之現在弄懂了qwq includeusing namespace std const int maxn 1e6 10,maxm 2e6 10,inf 1e8 int bg max...

P5021 賽道修建 貪心 二分

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

NOIP2018 P5021 賽道修建

看到題意描述第一反應就是先二分那個修建的 mm 條賽道中長度最小的賽道的長度 k 然後 o n o n 或 o n log n o nlogn 判斷。那麼怎麼判斷呢?對於每個結點,把所有傳上來的值 valval 放進乙個 multisetmultiset 其實這些值對答案有貢獻就兩種情況 val k...