Description
给出一个N个节点的无根树,每条边有非负边权,每个节点有三种颜色:黑,白,灰。
一个合法的无根树满足:树中不含有黑色结点或者含有至多一个白色节点。
现在希望你通过割掉几条树边,使得形成的若干树合法,并最小化割去树边权值的和。
Input
第一行一个正整数N,表示树的节点个数。
第二行N个整数Ai,表示i号节点的颜色,0 表示黑色,1表示白色,2表示灰色。
接下来N-1行每行三个整数Xi Yi Zi,表示一条连接Xi和Yi权为Zi的边。
Output
输出一个整数表示其最小代价。
Sample Input
5
0 1 1 1 0
1 2 5
1 3 3
5 2 5
2 4 16
Sample Output
10
样例解释:
花费10的代价删去边(1, 2)和边(2, 5)。
Data Constraint
20%的数据满足N≤10。
另外30%的数据满足N≤100,000,且保证树是一条链。
100%的数据满足N≤300,000,0≤Zi≤1,000,000,000,Ai∈{0,1,2}。
赛时
蒟蒟表示连20分暴力都没打出
正解
十分显然的树型dp,设f[i][0]表示以i为根的子树,除去已经割去的部分,满足没有黑色节点的最小代价; f[i][1]则表示没有白色
节点的最小代价;f[i][2]则表示有1或 0个白色节点的最小代价。
方程如上,自行理解,不多阐述。
之后有个恶心的东东是这道题用深搜会boom,boom,boom,系统栈会爆掉,所以要人工栈(自食其力,丰衣足食)
代码
#include<cstdio>
#include<cstring>
#define N 300007
using namespace std;
const long long INF=1e17;//ans会很大,所以“无穷大”也要很大
int n,cnt,a[N],head[N],d[N],fa[N];
long long f[N][3];
bool bz[N];
struct tree{
int to,nxt;
long long w;
}e[N<<2];
void add(int u,int v,long long w){
//链式前向星
e[++cnt].to=v;
e[cnt].w=w;
e[cnt].nxt=head[u];
head[u]=cnt