树的难题
题目连接
一眼DP,但想不到状态怎么设,在半醒半睡中度过了四十分钟
设f[i,j]表示第i个点,所在集合状态为j时的最小代价
j=0表示有0个黑色点
j=1表示有0个白色点
j=2表示有1个白色点
设a[i]为第i个点颜色黑色为0,白色为1,灰色为2
j为i的儿子,s为i与j之间的边的权值
当a[i]<>0时
f[i,0]为
当a[i]<>1时
f[i,1]为
当a[i]=1时,i所在集合中唯一一个白点显然为i
所以与i联通i的儿子的集合都不能有白点
所以f[i,2]为
如果a[i]不为1,就要从儿子的集合中钦定一个集合有白点与i联通
var
i1,i,j,n,t,x,y,z,so,ct,kk1:longint;
op1,op2,kk,ans,maxp:int64;
h,a,zz,fa:array[1..300000]of longint;
f:array[1..300000,0..2]of int64;
g,la,ss:array[1..600000]of longint;
function min(x,y:int64):int64;
begin
if x<y then exit(x)
else exit(y);
end;
procedure ad(x,y,z:longint);
begin
inc(so);
g[so]:=y;
la[so]:=h[x];
ss[so]:=z;
h[x]:=so;
end;
procedure mt(x:longint);
var
i:longint;
begin
i:=h[x];
while i<>0 do
begin
if g[i]<>fa[x] then
begin
inc(ct);
zz[ct]:=g[i];
fa[g[i]]:=x;
mt(g[i]);
end;
i:=la[i];
end;
end;
begin
readln(t);
maxp:=300000000000000;
for i1:=1 to t do
begin
fillchar(h,sizeof(h),0);
fillchar(fa,sizeof(fa),0);
fillchar(f,sizeof(f),0);
ct:=1;
so:=0;
zz[1]:=1;
readln(n);
for i:=1 to n do read(a[i]);
for i:=1 to n-1 do
begin
readln(x,y,z);
ad(x,y,z);
ad(y,x,z);
end;
mt(1);
for i:=n downto 1 do
begin
if a[zz[i]]=0 then f[zz[i],0]:=maxp;
if a[zz[i]]=1 then f[zz[i],1]:=maxp;
j:=h[zz[i]];
kk:=0;
kk1:=0;
while j<>0 do
begin
if g[j]<>fa[zz[i]] then
begin
if a[zz[i]]<>0 then
begin
f[zz[i],0]:=f[zz[i],0]+min(f[g[j],0],
min(f[g[j],1]+ss[j],f[g[j],2]+ss[j]));
end;
if a[zz[i]]<>1 then f[zz[i],1]:=f[zz[i],1]+min(f[g[j],1],
min(f[g[j],0]+ss[j],f[g[j],2]+ss[j]));
if a[zz[i]]=1 then
begin
f[zz[i],2]:=f[zz[i],2]+min(f[g[j],0]+ss[j],
min(f[g[j],1],f[g[j],2]+ss[j]));
end
else
begin
if (kk1=0) then
begin
kk1:=g[j];
op1:=min(f[g[j],1],min(f[g[j],0],f[g[j],2])+ss[j]);
end
else
begin
op2:=min(f[g[j],1],min(f[g[j],0],f[g[j],2])+ss[j]);
if op2-f[g[j],2]>op1-f[kk1,2] then
begin
kk:=kk+op1;
kk1:=g[j];
op1:=op2;
end
else kk:=kk+op2;
end;
end;
end;
j:=la[j];
end;
if kk1>0 then kk:=kk+f[kk1,2];
if a[zz[i]]<>1 then f[zz[i],2]:=kk;
end;
ans:=min(min(f[1,0],f[1,1]),f[1,2]);
writeln(ans);
end;
end.