CF375E Red and Black Tree

Link
单纯形是不可能的,这辈子都不可能单纯形的。
考虑树形dp,设\(f_{u,k,p}\)为在\(u\)子树内选\(k\)个黑点,\(u\)选的黑点是\(p\)的最小代价。
转移和树形背包差不多,不妨设\(v\in son_u\),考虑合并\(f_{u,i,p},f_{v,j,q}\)
\(p=q\),则\(f_{u,i,p}+f_{v,j,p}\rightarrow f_{u,i+j,p}\)
\(q\)\(v\)子树内,则此时\(p\)一定不在\(v\)子树内,\(f_{u,i,p}+f_{v,j,q}\rightarrow f_{u,i+j,p}\)
\(q\)\(v\)子树外,不难发现此时若\(p\ne q\)则一定不优,因此不予考虑。

#include<cstdio>
#include<vector>
#include<cstring>
#include<utility>
using i16=short;
using i64=long long;
using pi=std::pair<int,int>;
const int N=507;const i16 inf=16383;
int n,x,dfn[N],size[N],col[N],ban[N][N];i16 f[N][N][N],t[N][N];std::vector<pi>e[N];
int read(){int x;scanf("%d",&x);return x;}
void dfs1(int u,int f,int r,i64 d)
{
    ban[u][r]=d>x;
    for(auto[v,w]:e[u]) if(v^f) dfs1(v,u,r,d+w);
}
void dfs2(int u,int f)
{
    static int t=0;dfn[u]=++t;
    for(auto[v,w]:e[u]) if(v^f) dfs2(v,u);
}
void dp(int u,int fa)
{
    size[u]=1;f[u][col[u]][dfn[u]]=inf,f[u][!col[u]][dfn[u]]=1;
    for(int i=1;i<=n;++i) if(i^u) if(f[u][1][dfn[i]]=inf,ban[u][i]) f[u][0][dfn[i]]=inf;
    for(auto[v,w]:e[u])
    {
	if(v==fa) continue;
	dp(v,u),memset(t,0x3f,sizeof t);
	for(int j=0;j<=size[v];++j)
	{
	    i16 mn=inf;
	    for(int k=dfn[v];k<dfn[v]+size[v];++k) mn=std::min(mn,f[v][j][k]);
	    for(int i=0;i<=size[u];++i)
		for(int k=1;k<=n;++k)
		{
		    t[i+j][k]=std::min(t[i+j][k],(i16)(f[u][i][k]+f[v][j][k]));
		    if(k<dfn[v]||k>=dfn[v]+size[v]) t[i+j][k]=std::min(t[i+j][k],(i16)(f[u][i][k]+mn));
		}
	}
	size[u]+=size[v],memcpy(f[u],t,sizeof t);
    }
}

int main()
{
    n=read(),x=read();i16 num=0;
    for(int i=1;i<=n;++i) num+=col[i]=read();
    for(int i=1,u,v,w;i<n;++i) u=read(),v=read(),w=read(),e[u].push_back({v,w}),e[v].push_back({u,w});
    for(int i=1;i<=n;++i) dfs1(i,0,i,0);
    dfs2(1,0),dp(1,0);
    for(int i=0;i<=n;++i) for(int j=1;j<=n;++j) if(num>=f[1][i][j]) return !printf("%d",i);
    return puts("-1"),0;
}
posted @ 2020-04-07 11:20  Shiina_Mashiro  阅读(181)  评论(0编辑  收藏  举报