猫咪们狂欢

watersail / 2024-08-06 / 原文

  • 考场上感觉就是网络流,可惜建不出模
  • 最大权值闭合子图模型
  • 最小割的本质其实是点的划分,连接两个集合的点的边构成割集;在本题中,这恰好对应了点的选择与否
  • 首先强制将所有“狂欢猫”安排在第一棵树上,简化问题
  • 你希望建立【i和j都选可以推出k】的模型,虽然没有办法直接构建,但你可以让一个虚拟节点同时连向i和j,在最大权值闭合子图模型中,若i和j都被选择,则可以间接推出k一定被选择,否则答案一定不优
点击查看代码
#include <bits/stdc++.h>
using namespace std;
vector<int>a[3005];
vector<int>c[3005];
vector<int>d[3005];
int w[3005],s,t,pr1[3005],pr2[3005];
int q[3005],l[3005];
bool v[3005];
bool b[1005];
void update()
{
	int p=t;
	while(p!=s)
	{
		c[pr1[p]][pr2[p]]-=l[t];
		c[p][d[pr1[p]][pr2[p]]]+=l[t];
		p=pr1[p];
	}
}
int EK()
{
	memset(v,false,sizeof(v));
	q[1]=s;
	l[s]=INT_MAX;
	int L=0,r=1;
	while(L<r)
	{
		L++;
		int n1=q[L];
		for(int i=0;i<a[n1].size();i++)
		{
			if(v[a[n1][i]]==false&&c[n1][i]>0)
			{
				r++;
				q[r]=a[n1][i];
				v[a[n1][i]]=true;
				l[a[n1][i]]=min(l[n1],c[n1][i]);
				pr1[a[n1][i]]=n1;
				pr2[a[n1][i]]=i;
				if(a[n1][i]==t)
				{
					update();
					return l[a[n1][i]];
				}
			}
		}
	}
	return 0;
}
void add(int u,int v,int w)
{
	a[u].push_back(v);
	a[v].push_back(u);
	c[u].push_back(w);
	c[v].push_back(0);
	d[u].push_back(a[v].size()-1);
	d[v].push_back(a[u].size()-1);
}
int main()
{
	ios::sync_with_stdio(false);
	cin.tie(0);
	int T;
	cin>>T;
	while(T--)
	{
		int n,k;
		cin>>n>>k;
		memset(b,false,sizeof(b));
		memset(w,0,sizeof(w));
		for(int i=0;i<3*n;i++)
		{
			a[i].clear();
			c[i].clear();
			d[i].clear();
		}
		for(int i=1;i<=k;i++)
		{
			int x;
			cin>>x;
			b[x]=true;
		}
		int ans=0;
		for(int i=1;i<n;i++)
		{
			int u,v,W;
			cin>>u>>v>>W;
			if(b[u]&&b[v])
			{
				ans+=W;
				add(n+i,u,INT_MAX);
				add(n+i,v,INT_MAX);
				w[n+i]+=W;
				w[u]-=W;
				w[v]-=W;
			}
		}
		for(int i=1;i<n;i++)
		{
			int u,v,W;
			cin>>u>>v>>W;
			if(b[u]&&b[v])
			{
				add(2*n+i,u,INT_MAX);
				add(2*n+i,v,INT_MAX);
				w[2*n+i]+=W;
			}
		}
		s=0;
		t=3*n;
		for(int i=1;i<3*n;i++)
		{
			if(w[i]>0)
			{
				ans+=w[i];
				add(s,i,w[i]);
			}
			else if(w[i]<0)
			{
				add(i,t,-w[i]);
			}
		}
		int tmp;
		while(tmp=EK())
		{
			ans-=tmp;
		}
		cout<<ans<<endl;
	}
	return 0;
}