樹的難題
題目連接
一眼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.