给定树上2k个点两两配对,求距离和最大值。1e6
首先这种1e6的树上的题,一般都是$O(n)$的,所以两个思路,要么是DP,要么是贪心扫一遍。
比如说这个题,首先就是对于每对点,我尽量把lca往上提,这样就能保证答案最大值,然后每往上抬一个,只要是边他的贡献就是1,所以我们可以dfs,策略是能往上抬就往上抬,带着一堆点伸出的边,如果能外边有足够配对的点,那就往上抬,如果没有,我就两两就地配对。
然后就是比较帅气的AC了。
#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
const int N=100010;
int fr[N],fa[N],f[N],size[N],dep[N],a[N],b[N],p[N],n,k,s,tt,tot;
long long ans;
bool v[N];
struct node{int to,pr;}mo[N*2];
inline int rd()
{
int s=0,w=1;
char cc=getchar();
for(;cc<'0'||cc>'9';cc=getchar()) if(cc=='-') w=-1;
for(;cc>='0'&&cc<='9';cc=getchar()) s=(s<<3)+(s<<1)+cc-'0';
return s*w;
}
void add(int x,int y)
{
mo[++tt]=(node){y,fr[x]};
fr[x]=tt;
}
void dfs(int x)
{
for(int i=fr[x];i;i=mo[i].pr)
{
int to=mo[i].to;
if(to==fa[x])continue;
fa[to]=x;
dfs(to);
f[x]+=f[to]+min(size[to],2*k-size[to]);
size[x]+=size[to];
}
//cout<<x<<" "<<size[x]<<endl;
}
int main()
{
n=rd(),k=rd(),s=rd();
for(int i=1;i<=k*2;i++) p[i]=rd(),size[p[i]]=1;
for(int i=1;i<n;i++)
{
int x=rd(),y=rd();
add(x,y);add(y,x);
}
dfs(1);
printf("%d\n",f[1]);
}
/*
g++ 2.cpp -o 2 -O2
./2
7 2 0
1 5 6 2
1 3
3 2
4 5
3 7
4 3
4 6
*/
知识兔View Code