分析:这个题一眼看上去很难,但是正着做不行,我们换个角度:考虑每条边的贡献
因为是一棵树,所以一条边把树分成两个集合,假如左边有x个学校,右边有y个学校
贪心地想,让每条边在学校的路径上最多,所以贡献为min(x,y)
具体实现:一次dfs即可,复杂度O(N)
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
#include <stdio.h> #include <iostream> #include <algorithm> #include <string.h> #include <vector> #include <math.h> #include <stack> #include <map> using namespace std; typedef long long LL; const int N = 2e5+5; const int INF = 0x3f3f3f3f; const LL mod = 1ll<<32; int head[N],tot,sum[N],n,k; struct Edge{ int v,next; }edge[N<<1]; void add(int u,int v){ edge[tot].v=v; edge[tot].next=head[u]; head[u]=tot++; } LL ans; void dfs(int u,int f){ for(int i=head[u];~i;i=edge[i].next){ int v=edge[i].v; if(v==f)continue; dfs(v,u); ans+=min(k-sum[v],sum[v]); sum[u]+=sum[v]; } } int main(){ scanf("%d%d",&n,&k);k<<=1; memset(head,-1,sizeof(head)); for(int i=1;i<=k;++i){ int u;scanf("%d",&u); ++sum[u]; } for(int i=1;i<n;++i){ int u,v;scanf("%d%d",&u,&v); add(u,v);add(v,u); } dfs(1,0); printf("%I64d\n",ans); return 0; }