(第十四届蓝桥杯真题)砍树

 样例输入:

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

样例输出:

4

分析:由于题目中说明这个图是一棵树,所以任意两点之间的路径都是唯一的,那么我们要想使得u和v在不同的连通块中,我们只需要将其两点之间路径上的任意一条边删除即可,那么对于题目中所给的m个点对,我们都要将其分为两部分,那么可以这样考虑,假如删除某条边可以使得x个点对分离,那么这条边的贡献就是x,那么问题就转化为树上差分问题了,对于任意一个点对(u,v),这两点之间路径上的任意一条边权都会因为(u,v)的存在而+1,也就是说路径上的任意一条边删除即可使得u、v分离,那么我么可以转化为对于求解编号最大的边使得边权为m的问题,我们可以直接遍历每条边的权值,找到边权等于m的编号最大的边即可。

如果不懂树上差分是什么的小伙伴可以看下这里:(2条消息) 树上差分(点差分/边差分)_AC__dream的博客-CSDN博客

代码:

#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
const int N=5e5+10;
int e[N],ne[N],h[N],idx;
int f[N][25],d[N],s[N];
int n,m;
void add(int x,int y)
{
	e[idx]=y;
	ne[idx]=h[x];
	h[x]=idx++;
}
void dfs(int x,int fa,int dd)
{
	f[x][0]=fa;
	d[x]=dd;
	for(int i=1;i<=20;i++)
		f[x][i]=f[f[x][i-1]][i-1];
	for(int i=h[x];i!=-1;i=ne[i])
	{
		int j=e[i];
		if(j==fa) continue;
		dfs(j,x,dd+1);
	}
}
int lca(int x,int y)
{
	if(d[x]=0;i--)
	if(d[f[x][i]]>=d[y])
		x=f[x][i];
	if(x==y) return x;
	for(int i=20;i>=0;i--)
	{
		if(f[x][i]!=f[y][i])
		{
			x=f[x][i];
			y=f[y][i];
		}
	}
	return f[x][0];
}
void update(int x,int fa,int id,int &ans)
{
	for(int i=h[x];i!=-1;i=ne[i])
	{
		int j=e[i];
		if(j==fa) continue;
		update(j,x,i,ans);
		s[x]+=s[j];
	}
	if(s[x]==m) ans=max(ans,id/2+1);
}
int main()
{
	cin>>n>>m;
	for(int i=1;i<=n;i++) h[i]=-1;
	for(int i=1;i

你可能感兴趣的:(蓝桥杯,职场和发展)