bzoj 4033 傳送門
此題用到了計算貢獻的方法,
將 多條路徑的路徑和 $->$ $\sum_^ w[i]*cnt[i]$
這樣我們由找出所有路徑再計算轉化成了對每條邊計算其的貢獻
由於所有節點只用2種選擇,接下來就是比較套路的樹形dp了
設 $dp[i][j]$ 為在以 $i$ 為根的子樹中,有$j$個黑點時的$max$。
這樣按照$dfs$序依次處理每個節點$x$,對子樹揹包$dp$,最後再加上$w_{}$的貢獻即可
#include usingnamespace
std;
typedef
long
long
ll;typedef pair
p;const
int maxn=2005*2
;vector
g[maxn];
ll n,k,dp[maxn][maxn],sz[maxn];
void tree_dp(int x,int
anc,ll val)
for(int i=0;i<=min(sz[x],k);i++) //統計貢獻
dp[x][i]+=val*((ll)i*(k-i)+(sz[x]-i)*((n-sz[x])-(k-i)));
}int
main()
tree_dp(
1,0,0
); printf(
"%lld
",dp[1
][k]);
return0;
}
1、計算貢獻的思想:
將多個整體拆分成每個個體$*$出現次數的和
只要能快速地計算出貢獻,依次考慮每個個體即可
2、樹形$dp$的套路和注意事項:
套路:樹形$dp$大部分時候都是依據$dfs$序在對子樹揹包$dp$
note:(1)揹包$dp$要從後往前更新,防止多次計算
(2)一般$size[x]$的更新都要放在對該子樹更新完之後
3、點集的劃分
該題的特殊性在於對點集嚴格劃分為2堆,才能直接算出每種點的個數
當出現對點集嚴格劃分的題目時,只要儲存乙個量,並考慮能否計算貢獻
bzoj4033(樹上染色)
樹上染色 有一棵點數為n的樹,樹邊有邊權。給你乙個在0 n之內的正整數k,你要在這棵樹中選擇k個點,將其染成黑色,並 將其他的n k個點染成白色。將所有點染色後,你會獲得黑點兩兩之間的距離加上白點兩兩之間距離的和的收益。問收益最大值是多少。input 第一行兩個整數n,k。接下來n 1行每行三個正整...
bzoj4033 HAOI2015 樹上染色
題目鏈結 有一棵點數為n的樹,樹邊有邊權。給你乙個在0 n之內的正整數k,你要在這棵樹中選擇k個點,將其染成黑色,並 將其他的n k個點染成白色。將所有點染色後,你會獲得黑點兩兩之間的距離加上白點兩兩之間距離的和的收益。問收益最大值是多少。第一行兩個整數n,k。接下來n 1行每行三個正整數fr,to...
bzoj4033 HAOI2015 樹上染色
有一棵點數為n的樹,樹邊有邊權。給你乙個在0 n之內的正整數k,你要在這棵樹中選擇k個點,將其染成黑色,並 將其他的n k個點染成白色。將所有點染色後,你會獲得黑點兩兩之間的距離加上白點兩兩之間距離的和的收益。問收益最大值是多少。輸入保證所有點之間是聯通的。n 2000,0 k n 來自 臥槽原來我...