【MX-S8-T2】配对
为方便描述,称
以下为我赛时的思考路径:
首先可以发现,一颗子树中的所有黑点肯定需要尽量匹配,最多剩下
然后我们考虑一个点
这样我们或许可以
令
现在我们需要最小化这个东西。我们可以做什么:
- 交换两个节点的颜色,它相当于给两个不同颜色的点取反;
- 如果
\sum c_i 是奇数,我们可以钦定一个不选,相当于给一个黑点取反。
这些全都是取反操作。所以我们设一个 DP,令
转移根据每个子树的奇偶性算贡献。
最终答案,钦定
具体看代码。
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N = 1e6 + 10;
struct node{
int to,w;
};
vector <node> G[N];
int n,c[N],f[N][3][2],g[N][3][2],sz[N],sum[N];
void dfs(int u,int fa){
sz[u] = c[u];
for(auto v : G[u]){
int to = v.to;
if(to == fa) continue;
dfs(to,u);sz[u] += sz[to];
}
}
void dp(int u,int fa){
f[u][0][0] = 0;
if(c[u]) f[u][1][0] = 0;
else f[u][0][1] = 0;
for(auto v : G[u]){
int to = v.to,w = v.w;
if(to == fa) continue;
dp(to,u);
memset(g[u],0x3f,sizeof(g[u]));
for(int p1 = 0;p1 <= 2;p1 ++){
for(int q1 = 0;q1 <= 1;q1 ++){
for(int p2 = 0;p2 <= 2;p2 ++){
for(int q2 = 0;q2 <= 1;q2 ++){
int x = p1 + p2,y = q1 + q2;
if(x > 2 || y > 1) continue;
g[u][x][y] = min(g[u][x][y],
f[to][p2][q2] + f[u][p1][q1]
+ w * ((sz[to] + p2 + q2) % 2 == 1));
}
}
}
}
memcpy(f[u],g[u],sizeof(g[u]));
}
}
signed main(){
cin >> n;
for(int i = 1;i <= n;i ++) cin >> c[i];
for(int i = 1;i < n;i ++){
int u,v,w;cin >> u >> v >> w;
G[u].push_back({v,w});
G[v].push_back({u,w});
}
dfs(1,0);
memset(f,0x3f,sizeof(f));
dp(1,0);
if(sz[1] % 2 == 0) cout << min(f[1][0][0],f[1][1][1]);
else cout << min(f[1][1][0],f[1][2][1]);
return 0;
}