CF1029E Tree with Small Distances

LXIII.CF1029E Tree with Small Distances

我们发现,如果一个点与\(1\)连了边,那么它的儿子们以及它的父亲都会变成合法的。

因此我们可以设\(f[i][0/1/2]\)表示:\(i\)的某个儿子中有边/\(i\)自己有边/\(i\)的父亲应该有边的最小值。

转移:

\(0\):可以从儿子的\(0\)\(1\)转移,且儿子中至少有一个为\(1\)(即,找到\(1\)\(0\)差最小的那个换成\(1\)

\(1\)\(0/1/2\)皆可,取\(\min\)即可。

\(2\)\(0/1\)\(\min\)

复杂度\(O(n)\)

最后说一下答案,应该是\(1\)的所有儿子的\((f[x][1]-1)\)的和,因为\(1\)的所有儿子都相当于连了一条免费的边。

代码:

#include<bits/stdc++.h>
using namespace std;
int n,head[1001000],cnt,f[1001000][3],res;//0:have a son;1:itself;2:have a father 
struct node{
	int to,next;
}edge[2001000];
void ae(int u,int v){
	edge[cnt].next=head[u],edge[cnt].to=v,head[u]=cnt++;
}
void dfs(int x,int fa){
	int mn=0x3f3f3f3f;
	f[x][1]=1;
	for(int i=head[x],y;i!=-1;i=edge[i].next){
		if((y=edge[i].to)==fa)continue;
		dfs(y,x);
		f[x][0]+=min(f[y][0],f[y][1]),mn=min(mn,f[y][1]-f[y][0]);
		f[x][1]+=min(f[y][0],min(f[y][1],f[y][2]));
		f[x][2]+=min(f[y][0],f[y][1]);
		if(x==1)res+=f[y][1]-1;
	}
	f[x][0]+=max(mn,0);
}
int main(){
	scanf("%d",&n),memset(head,-1,sizeof(head));
	for(int i=1,x,y;i<n;i++)scanf("%d%d",&x,&y),ae(x,y),ae(y,x);
	dfs(1,0);
	printf("%d\n",res);
	return 0;
} 

posted @ 2021-03-30 16:38  Troverld  阅读(34)  评论(0编辑  收藏  举报