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