其他分享
首页 > 其他分享> > DD摆磁铁

DD摆磁铁

作者:互联网

现在萨摩耶给了 DDDD 一棵树,树上有 2*m2∗m 个节点上有磁铁, DDDD 要把他们配对成 mm 对,为了让一对中两个磁铁的吸引减少,我们要使 \sum_{i=1}^{m}dis_{pair}∑
i=1
m

dis
pair

最大化

DDDD 想知道距离和最大为多少

输入格式
第一行两个整数分别表示 n,mn,m

第二行 2*m2∗m 个整数,表示哪些点上有磁铁

接下来 n-1n−1 行,每行两个整数表示 u_i,v_iu
i

,v
i

输出格式
一个整数表示最大化的距离和为多少

数据范围
对于 $20% $的数据, \(n \leq 10\)

对于 \(50\%\) 的数据, \(n \leq 1000\)

对于 \(100\%\) 的数据, \(n \leq 200000\)

输出时每行末尾的多余空格,不影响答案正确性

样例输入

7 2
1 2 5 6
1 3
2 3
4 5
3 7
4 3
4 6

样例输出

6

考虑一条边会被计算多少次。在最大的情况下,一条边会被算多少次,要看他的两条边所延伸出的子树有多大。
那么设一条边一端有a个,另一端有b个,那么最大的情况肯定让左右两端都经过这条边,也就加上\(\min(a,b)\)个
在具体的搜索中,设一个点为根,设\(sz_x\)为以x为子树的中有多少个特殊的店,然后\((u,v)\)这条边设\(u\)更接近根,那么答案加上\(\min(2m-sz_v,sz_v)\)

#include<bits/stdc++.h>
using namespace std;
const int N=2e5+5;
int n,m,a[N],sz[N],u,v;
vector<int>g[N];
long long cnt=0;
void sou(int x,int y)
{
	for(int i=0;i<g[x].size();i++)
	{
		if(g[x][i]!=y)
		{
			sou(g[x][i],x);
			sz[x]+=sz[g[x][i]];
			cnt+=min(sz[g[x][i]],m+m-sz[g[x][i]]);
		}
	}
}
int main()
{
	scanf("%d%d",&n,&m);
	for(int i=1;i<=m+m;i++)
		scanf("%d",a+i),sz[a[i]]=1;
	for(int i=1;i<n;i++)
	{
		scanf("%d%d",&u,&v);
		g[u].push_back(v);
		g[v].push_back(u);
	}
	sou(1,0);
	printf("%lld",cnt);
	return 0;
}

标签:磁铁,sz,int,DD,整数,leq,DDDD
来源: https://www.cnblogs.com/mekoszc/p/16270325.html