巨木之森(樹的路徑,貪心)

2021-10-24 06:47:16 字數 1951 閱讀 1163

巨木之森

給定一棵n

nn個結點的樹,m

mm塊錢。定義花費為從乙個點出發遍歷整棵樹所經過的路徑和。求最多能選擇多少個不同的起點使得花費總和≤

m\leq m

≤m。n≤1

05,m

≤1018

,wi≤

10

8n \leq 10^5, m \leq 10^,w_i \leq 10^8

n≤105,

m≤10

18,w

i​≤1

08這道題問的是路徑和,所以要從每條邊計算幾次入手。可以將樹畫成一條鏈,鏈的兩側有若干子樹的形狀,這樣問題會變得更加直觀。

我們很容易發現,在乙個花費中,一條鏈被計算1

11次,其餘邊權被計算2

22次。假設這條鏈的長度為len

lenle

n,整棵樹所有邊權和為tot

al

total

tota

l,則花費即為len

+2∗(

tota

l−le

n)=2

∗tot

al−l

en

.len+2*(total - len) = 2 * total - len.

len+2∗

(tot

al−l

en)=

2∗to

tal−

len.

我們根據式子,可以發現花費只與鏈的長度有關。因此,為了使每次花費最少,我們可以選取以起點為乙個端點的最長鏈。求出以每個點為起點的最長鏈,在從大到小遍歷一遍,統計出答案,問題就解決了。

**的書寫就是個套模板的過程。

#include

#include

#include

#include

using

namespace std;

typedef

long

long ll;

const

int n =

100010

, m =

2* n;

const ll inf =

2e18

;int n;

ll m;

int h[n]

, e[m]

, ne[m]

, idx;

ll w[m]

;ll d1[n]

, d2[n]

, p1[n]

, up[n]

, len[n]

;bool is_leaf[n]

;void

add(

int a,

int b,ll c)

ll dfs_d

(int u,

int father)

else

if(d>d2[u]

) d2[u]

= d;}if

(d1[u]

==-inf)

return d1[u];}

void

dfs_u

(int u,

int father)

}int

main()

tot *=2

;dfs_d(1

,-1)

;dfs_u(1

,-1)

; len[1]

= d1[1]

;for

(int i=

2;i<=n;i++

)sort

(len+

1,len+

1+n)

;int ans =0;

for(

int i=n;i>=

1;i--)}

printf

("%d\n"

,ans)

;return0;

}

牛客 6874 A 巨木之森 (樹的直徑)

鏈結 a 巨木之森 題意 每支小隊從每個點出發 遍歷完整顆樹的花費是走過路徑的和,要求在花費 m 以內,最多可以有多少個小隊遍歷完整顆樹。思路 可以求出每個點遍歷整棵樹的花費 排個序,從小到 就好了,關鍵在於求花費。可以發現,要想遍歷完整顆樹,再回到原來的位置,那麼就要把每條邊都走兩遍,但是現在不需...

好題 樹形dp 換根 A 巨木之森

傳送門 這題大概是我做的第一道換根dp的題目吧。其實還是挺容易的 題目大意 就是對於每個點,求以這個點為起點遍歷完全圖的最小代價.思路 首先一點 若要求回到起點,那麼代價就是 邊權累和 2 不要求回到起點,等價於我們選擇一條路徑。這路徑上的權值都只加一遍.其他邊還是加兩遍。那麼我們肯定是選擇離這個點...

BZOJ1907 樹的路徑覆蓋(貪心)

我是超連結 看上去像網路瘤題?嗯很明顯想多了,這可是一棵樹啊 然後陷入一臉不可做的狀態。翻翻翻 以某乙個點為根的子樹,這個點只有兩種狀態 拐彎 兩條簡單路徑在乙個點交匯成一條,折折折 和直上 一條路走到黑 我們優先滿足拐彎的情況,貪心!貪心策略是 只要當前點能成為拐點,就讓它成為拐點。也就是說,貪心...