/** 给定一棵树,要求给树边赋值[0,n-2],每个值只能使用一次 S = mex(u,v), mex(u,v)是u-v路径上没有出现过的编号最小的值 问使得S最大的赋值方式 由于很难直接统计答案,所以考虑统计每条边的贡献 包含(0)路径的贡献tot1是其左右子树size的乘积 包含(0,1)的路径的贡献tot2是其左右子树的size乘积 ...依次类推 显然:只包含(1,2)这样的路径是没有贡献的 那么原问题转化为如何分配[0,n-2],使得最后的乘积和最大 dp[u][v]表示路径(u,v)的贡献 ,O(n^2)的时间内求完即可 显然root不同,答案也会不同,所以先预处理出 size[root][u],表示以root为根时u的儿子大小 fa[root][u],表示以root为根时u的父亲 两重循环+记忆化搜索求出所有dp[u][v] */ #include<bits/stdc++.h> using namespace std; #define N 3005 #define ll long long vector<int>G[N]; ll n,dp[N][N],size[N][N],fa[N][N]; void dfs(int u,int pre,int root){ size[root][u]=1;fa[root][u]=pre; for(auto v:G[u]){ if(v==pre)continue; dfs(v,u,root); size[root][u]+=size[root][v]; } } ll solve(int u,int v){ if(u==v)return 0; if(dp[u][v]!=-1)return dp[u][v]; dp[u][v]=size[u][v]*size[v][u] +max(solve(u,fa[u][v]),solve(v,fa[v][u])); return dp[u][v]; } int main(){ cin>>n; for(int i=1;i<n;i++){ int u,v; cin>>u>>v; G[u].push_back(v); G[v].push_back(u); } for(int root=1;root<=n;root++) dfs(root,0,root); memset(dp,-1,sizeof dp); ll ans=0; for(int u=1;u<=n;u++) for(int v=1;v<=n;v++) ans=max(ans,solve(u,v)); cout<<ans<<' '; }