Xenon’s Attack on the Gangs
题意: 给你一棵树,将0~n-2一一赋值给n-1条边,则S最大可能取值
S
=
∑
1
≤
u
<
v
≤
n
m
e
x
(
u
,
v
)
S=\sum_{1\le u< v\le n}mex(u,v)
S=∑1≤u<v≤nmex(u,v)
mex(u,v)表示u到v的路径中未出现的最小非负数
思路: 这里推荐一个视频题解,个人觉得讲得非常好 qscqesze
S
=
∑
1
≤
u
<
v
≤
n
m
e
x
(
u
,
v
)
=
∑
1
≤
x
≤
n
(
∑
m
e
x
(
u
,
v
)
=
x
x
)
=
∑
1
≤
x
≤
n
(
∑
m
e
x
(
u
,
v
)
≥
x
1
)
S=\sum_{1\le u< v\le n}mex(u,v)=\sum_{1\le x\le n}(\sum_{mex(u,v)=x}x)=\sum_{1\le x \le n}(\sum_{mex(u,v)\ge x}1)
S=∑1≤u<v≤nmex(u,v)=∑1≤x≤n(∑mex(u,v)=xx)=∑1≤x≤n(∑mex(u,v)≥x1)
所以我们只需要考虑每条边的贡献即可,每条边要有贡献。
首先我们可以看0所在的边的两个端点u,v,则0的贡献为size[v][u]*size[u][v],接着看1,我们发现只有将0,1连接在一起贡献才会尽可能的大,所以我们要使得[0,m]分布在一条链上。所以我们可以对这棵树进行dp,dp[u][v]表示以u,v为端点的链
#include<bits/stdc++.h>
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<stack>
#include<queue>
using namespace std;
typedef long long ll;
const int mod=1e9+7;
const int N=3e3+5;
vector<int>G[N];
int fa[N][N],sz[N][N];
ll dp[N][N],ans;
void dfs(int u,int f,int root){
sz[root][u]=1;
fa[root][u]=f;
for(auto v: G[u]){
if(v==f)
continue;
dfs(v,u,root);
sz[root][u]+=sz[root][v];
}
}
ll sl(int x,int y){
if(x==y)
return 0;
if(dp[x][y]!=-1)
return dp[x][y];
dp[x][y]=1ll*sz[y][x]*sz[x][y]+max(sl(fa[y][x],y),sl(x,fa[x][y]));
return dp[x][y];
}
int main(){
#ifdef Mizp
freopen("in.txt","r",stdin);
#endif
std::ios::sync_with_stdio(0);
int n;
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 i=1;i<=n;i++){
dfs(i,0,i);
}
memset(dp,-1,sizeof dp);
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
ans=max(ans,sl(i,j));
}
}
cout<<ans<<endl;
return 0;
}