BZOJ4033 HAOI2015 樹上染色

2022-05-09 16:59:52 字數 1738 閱讀 3375

[bzoj4033][haoi2015]樹上染色

試題描述

有一棵點數為n的樹,樹邊有邊權。給你乙個在0~n之內的正整數k,你要在這棵樹中選擇k個點,將其染成黑色,並

將其他的n-k個點染成白色。將所有點染色後,你會獲得黑點兩兩之間的距離加上白點兩兩之間距離的和的收益。

問收益最大值是多少。

輸入

第一行兩個整數n,k。

接下來n-1行每行三個正整數fr,to,dis,表示該樹中存在一條長度為dis的邊(fr,to)。

輸入保證所有點之間是聯通的。

n<=2000,0<=k<=n

輸出

輸出乙個正整數,表示收益的最大值。

輸入示例

521

2315

1231

242

輸出示例

17

資料規模及約定

見「輸入

題解

樹形 dp,設 f(i, j) 表示對於子樹 i,選 j 個黑點所能得到的邊的最大貢獻,注意這裡邊的貢獻是全域性的,不是只考慮子樹內部的,這樣做比較方便轉移。

那麼在轉移的時候,對於節點 u,我們在樹上做揹包,就是列舉每個兒子分別選幾個黑點然後合併。這樣看上去很暴力,但是我們可以證明總轉移複雜度不超過 o(n2)。其實就是要證明 o(∑u=1..n∑v,w是u的兒子siz[v]·siz[w]) = o(n2)。我們不妨把「∑v,w是u的兒子siz[v]·siz[w]」這一部分看做每次從 u 的每個子樹中任選兩個點 (a, b) 使得 a 和 b 的最近公公祖先恰好為 u 的方案數,那麼每個節點只可能一次成為最近公公祖先,那麼整個「∑u=1..n∑v,w是u的兒子siz[v]·siz[w]」其實就是樹中點對個數,所以是 n2 的。

#include #include #include #include #include #include using namespace std;

#define ll long long

ll read()

while(isdigit(c))

return x * f;

}#define maxn 2010

#define maxm 4010

int n, k, m, head[maxn], nxt[maxm], to[maxm];

ll dist[maxm];

void addedge(int a, int b, ll c)

ll f[maxn][maxn];

int siz[maxn];

void build(int u, int fa)

if(siz[u] == 1)

int sum = 1;

f[u][0] = f[u][1] = 0;

for(int e = head[u]; e; e = nxt[e]) if(to[e] != fa)

return ;

}int main()

memset(f, -1, sizeof(f));

build(1, 0);

printf("%lld\n", f[1][k]);

return 0;

}

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

BZOJ 4033 HAOI2015 樹上染色

time limit 10 sec memory limit 256 mb submit 2569 solved 1088 submit status discuss description 有一棵點數為n的樹,樹邊有邊權。給你乙個在0 n之內的正整數k,你要在這棵樹中選擇k個點,將其染成黑色,並 ...