2019.07.10【NOIP提高組】模擬 A 組T1 樹的難題

樹的難題

題目連接

一眼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]爲\sum min(f[j,0],f[j,1]+s,f[j,2]+s)

 

當a[i]<>1時

f[i,1]爲\sum min(f[j,0]+s,f[j,1],f[j,2]+s)

 

當a[i]=1時,i所在集合中唯一一個白點顯然爲i

所以與i聯通i的兒子的集合都不能有白點

所以f[i,2]爲\sum min(f[j,0]+s,f[j,1],f[j,2]+s)

 

如果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.

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章