正题
BZOJBZOJBZOJ题目链接:https://www.lydsy.com/JudgeOnline/problem.php?id=3257
题目大意
一棵树上的节点有333种颜色,有边权。
选择一些边割掉使得森林中每棵树只有一个白点或没有黑点。
求割掉的边的最小值。
解题思路
定义fi,statef_{i,state}fi,state表示iii的子树中割掉后森林所有的树都满足条件且目前子树连接的点状态为statestatestate。
下面给出状态
状态 | 白 | 黑 |
---|---|---|
000 | 000 | 000 |
111 | 0∼∞0\sim \infty0∼∞ | 000 |
222 | 000 | 0∼∞0\sim \infty0∼∞ |
333 | 0or10\ or\ 10 or 1 | 000 |
444 | 0or10\ or\ 10 or 1 | 0∼∞0\sim \infty0∼∞ |
然后如果对于状态s1s1s1和s2s2s2。若s1s1s1可以转移到s2s2s2
fx,s1=fx,s1+fy,s2f_{x,s1}=f_{x,s1}+f_{y,s2}fx,s1=fx,s1+fy,s2
否则
fx,s1=fx,s1+fy,s2+wx,yf_{x,s1}=f_{x,s1}+f_{y,s2}+w_{x,y}fx,s1=fx,s1+fy,s2+wx,y
然后要注意后两个状态的白色只能传一个白色上来所有需要特殊处理
需要注意的是在野鸡jzojjzojjzoj中会爆栈,这里是先进行一次拓扑排序再dpdpdp
codecodecode
#include<cstdio>
#include<cstring>
#include<algorithm>
#define xf(z) f[x][z]
#define yf(z) f[y][z]
#define min3(a1,a2,a3) min(min(a1,a2),a3)
#define min4(a1,a2,a3,a4) min(min(a1,a2),min(a3,a4))
#define min5(a1,a2,a3,a4,a5) min(min(min(a1,a2),min(a3,a4)),a5)
#define ll long long
using namespace std;
const ll N=301000,inf=1e18;
struct Edge_node{ll to,next,w;
}a[N*2];
ll T,n,c[N],ls[N],tot,f[N][5],q[N],fa[N];
void addl(ll x,ll y,ll w)
{a[++tot].to=y;a[tot].next=ls[x];ls[x]=tot;a[tot].w=w;
}
void dfs()
{int head=1,tail=0;q[++tail]=1;while(head<=tail){int x=q[head++];for(int i=ls[x];i;i=a[i].next){int y=a[i].to;if(y==fa[x]) continue;fa[y]=x;q[++tail]=y;}}for(int i=tail;i>=1;i--){int x=q[i];ll white1=0,white2=0;for(ll i=ls[x];i;i=a[i].next){ll y=a[i].to,z;if(y==fa[x]) continue;xf(0)+=min(min4(yf(1),yf(2),yf(3),yf(4))+a[i].w,yf(0));xf(1)+=min(min3(yf(0),yf(1),yf(2)),min(yf(3),yf(4))+a[i].w);xf(2)+=(z=min(yf(0),min4(yf(1),yf(2),yf(3),yf(4))+a[i].w));white1=max(white1,z-yf(2));xf(3)+=(z=min(min(yf(0),yf(4)),min3(yf(3),yf(2),yf(1))+a[i].w));white2=max(white2,z-min(yf(3),yf(2)));xf(4)+=min(min(yf(0),yf(4)),min3(yf(1),yf(2),yf(3))+a[i].w);}xf(2)-=white1;xf(3)-=white2;if(c[x]==1){xf(3)=xf(4);xf(2)=xf(0);xf(1)=min3(xf(0),xf(1),xf(2));xf(0)=xf(4)=inf;}else if(c[x]==0){xf(3)=min3(xf(3),xf(2),xf(0));xf(0)=xf(1)=xf(2)=inf;}xf(1)=min3(xf(1),xf(0),xf(2));xf(2)=min(xf(2),xf(0));xf(3)=min3(xf(3),xf(2),xf(0));xf(4)=min(xf(4),xf(0));}
}
int main()
{scanf("%lld",&T);while(T--){memset(f,0,sizeof(f));memset(ls,0,sizeof(ls));tot=0;scanf("%lld",&n);for(ll i=1;i<=n;i++)scanf("%lld",&c[i]);for(ll i=1;i<n;i++){ll x,y,w;scanf("%lld%lld%lld",&x,&y,&w);addl(x,y,w);addl(y,x,w);}dfs();printf("%lld\n",min5(f[1][0],f[1][1],f[1][2],f[1][3],f[1][4]));}
}