https://www.lydsy.com/JudgeOnline/problem.php?id=3257
给定一个含有 n n n个节点的树,每个节点有自己的颜色(黑白灰),每条相连的边都有自己的权值
定义一棵树满足以下条件即为一棵合法的树:
你可以选择花费一条边的权值的代价来割除这条边
求将该树变成一片合法的森林(即割出来的树也必须合法)的最小修改代价
n ≤ 3 × 1 0 5 n\leq 3\times 10^5 n≤3×105
把1看成根,然后设方程 f [ i ] [ 0 / 1 / 2 ] f[i][0/1/2] f[i][0/1/2]表示以 i i i为根,以这个节点为根的子树无黑点/无白点/有一个白点的最小代价,转移显然
需要注意的是,由于 G M O J GMOJ GMOJ(即 J Z O J JZOJ JZOJ)很垃圾,所以要用拓扑序来 d p dp dp,否则会爆栈。
时间复杂度: O ( n ) O(n) O(n)
#include
#include
#include
#include
#define N 300010
using namespace std;int n,a[N],tot,l[N],d[N],q[N],fa[N];
long long f[N][3];
struct node{int next,to,w;}e[N<<1];
inline void add(int u,int v,int w){e[++tot]=(node){l[u],v,w};l[u]=tot;return;}
inline long long read()
{
char c;int f=0,d=1;
while(c=getchar(),!isdigit(c)) if(c=='-') d=-1;f=(f<<3)+(f<<1)+c-48;
while(c=getchar(),isdigit(c)) f=(f<<3)+(f<<1)+c-48;
return d*f;
}
inline void dfs()
{
int head=1,tail=0;q[++tail]=1;
while(head<=tail)
{
int x=q[head++];
for(register int i=l[x],y;i;i=e[i].next)
{
y=e[i].to;
if(y==fa[x]) continue;
fa[y]=x;q[++tail]=y;d[y]=e[i].w;
}
}
for(register int i=tail;i>0;i--)
{
int x=q[i];
if(a[x]==0)
{
f[x][0]=1LL<<50LL;
long long ans1=0,ans2=0;
for(register int i=l[x];i;i=e[i].next)
{
int y=e[i].to;
if(y==fa[x]) continue;
ans1+=min(f[y][1],min(f[y][0],f[y][2])+d[y]);
}
f[x][1]=ans1;
ans2=ans1;
for(register int i=l[x];i;i=e[i].next)
{
int y=e[i].to;
if(y==fa[x]) continue;
ans2=min(ans2,ans1-min(f[y][1],min(f[y][0],f[y][2])+d[y])+f[y][2]);
}
f[x][2]=ans2;
}
if(a[x]==1)
{
f[x][1]=1LL<<50LL;
long long ans0=0,ans2=0;
for(register int i=l[x];i;i=e[i].next)
{
int y=e[i].to;
if(y==fa[x]) continue;
ans0+=min(f[y][0],min(f[y][1],f[y][2])+d[y]);
ans2+=min(f[y][1],min(f[y][0],f[y][2])+d[y]);
}
f[x][0]=ans0;
f[x][2]=ans2;
}
if(a[x]==2)
{
long long ans0=0,ans1=0,ans2=0;
for(register int i=l[x];i;i=e[i].next)
{
int y=e[i].to;
if(y==fa[x]) continue;
ans0+=min(f[y][0],min(f[y][1],f[y][2])+d[y]);
ans1+=min(f[y][1],min(f[y][0],f[y][2])+d[y]);
}
ans2=ans1;
for(register int i=l[x];i;i=e[i].next)
{
int y=e[i].to;
if(y==fa[x]) continue;
ans2=min(ans2,ans1-min(f[y][1],min(f[y][0],f[y][2])+d[y])+f[y][2]);
}
f[x][0]=ans0;
f[x][1]=ans1;
f[x][2]=ans2;
}
}
return;
}
signed main()
{
for(int t=read();t--;tot=0)
{
memset(l,0,sizeof(l));
n=read();
for(register int i=1;i<=n;i++) a[i]=read(),f[i][0]=f[i][1]=f[i][2]=1LL<<50LL;
for(register int i=1,u,v,w;i<n;i++)
{
u=read();v=read();w=read();
add(u,v,w);add(v,u,w);
}
d[1]=0;dfs();
printf("%lld\n",min(f[1][0],min(f[1][1],f[1][2])));
}
}