BZOJ 4033 樹上染色

2022-05-13 11:08:13 字數 1248 閱讀 4545

bzoj 4033 傳送門

此題用到了計算貢獻的方法,

將 多條路徑的路徑和  $->$ $\sum_^ w[i]*cnt[i]$

這樣我們由找出所有路徑再計算轉化成了對每條邊計算其的貢獻

由於所有節點只用2種選擇,接下來就是比較套路的樹形dp了

設 $dp[i][j]$ 為在以 $i$ 為根的子樹中,有$j$個黑點時的$max$。

這樣按照$dfs$序依次處理每個節點$x$,對子樹揹包$dp$,最後再加上$w_{}$的貢獻即可

#include using

namespace

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 來自 臥槽原來我...