2024.2.25模拟赛T2题解

题目

枚举根之后,考虑每次连边的贡献,通过贡献算出每个点的权值,每次找出权值最大的点,又要保证父亲在儿子之前,所以将父亲和儿子合并,权值也合并一下即可

code

#include<bits/stdc++.h>
using namespace std;
#define N 2005
int ans,n,k;
int sz[N],deg[N],du[N],fu[N],f[N],h[N];
struct AB{
	int a,b,n;
}d[N*2];
void cun(int x,int y){
	d[++k]=(AB){x,y,h[x]},h[x]=k;
}
struct A{
	int x,y,z;
};
bool operator < (A x,A y){
	return x.z*y.y<x.y*y.z;
}
priority_queue<A> q;
void dfs(int x,int fa){
	sz[x]=1,deg[x]=du[x]-2,fu[x]=fa;
	for(int i=h[x];i;i=d[i].n){
		int y=d[i].b;
		if(y==fa) continue;
		dfs(y,x);
	}
}
int find(int x){
	if(f[x]==x) return x;
	return f[x]=find(f[x]);
}
int solve(int rt){
	int ans=0;
	dfs(rt,0);deg[rt]+=2;
	for(int i=1;i<=n;i++){
		f[i]=i;
		if(i!=rt) q.push({i,sz[i],deg[i]});
	}
	while(!q.empty()){
		A p=q.top();q.pop();
		if(sz[p.x]!=p.y) continue;
		int fa=find(fu[p.x]),x=p.x;
		assert(x);
		ans+=sz[x]*deg[fa],sz[fa]+=sz[x],deg[fa]+=deg[x],f[find(x)]=fa;
		if(fa!=rt) q.push({fa,sz[fa],deg[fa]});
	}
	return ans;
}
int main(){
	scanf("%d",&n);
	for(int i=1,x,y;i<n;i++){
		scanf("%d%d",&x,&y);
		x++,y++;
		cun(x,y),cun(y,x),du[x]++,du[y]++;
	}
	for(int i=1;i<=n;i++){
		ans=max(ans,solve(i));
	}
	printf("%lld\n",ans+n-1);
	return 0;
}
posted @ 2024-02-26 21:26  hubingshan  阅读(24)  评论(0)    收藏  举报