题目大意
现在有一棵 (n (2leq n leq 3000)) 个结点的树,每条边分配了一个 ([0,2]) 的整数权值 (w) , 所有分配的整数都是不同的,并且每个整数都能分配给某条边。
定义: (S_{path(s,t)}=mex_{(u,v)in path(s,t)} w(u,v))
要求最大化 (sumlimits_{1leq s < t leq n} S_{path(s,t)})
题解
考虑每条边的贡献,我们从0开始分配边权。
假设我们令 (w(u_0,v_0)=0) , 令边 ((u_0,v_0)) 把树分成了两个点集, 其中含有 (u) 的点集的大小是 (Size(u_0)), 含有 (v_0) 的点集的大小是 (Size(v_0))。则令 (w(u_0,v_0)=0) 后,对于所有跨越 ((u_0,v_0)) 的路径,其 (mex) 都大于 (0),贡献是 (Size(u_0) imes Size(v_0))。然后我们去分配边权1,令 (w(u_1,v_1)=1),因为是 (mex),所以此时只对同时经过 ((u_0,v_0)) 和 ((u_1,v_1)) 的边有贡献。显然,((u_1,v_1)) 应该与 ((u_0,v_0)) 相连才更优。以此类推,我们将最终把一条树链上的每条边分配边权,不在这条树链上的边给它分配边权也对答案没有贡献。且这条链上的边权一定是先减后增,否则易证答案不会更优。
因为链上的边权是先减后增,所以每次是按边权从小到大给链的两端分配边权。这样的话和区间dp有点类似。设 (dp[u][v]) 表示已经给 (usim v) 这条树链分配了边权 (0sim l-1)所得到的最大答案。设(Size_{root}(u)) 表示以 (root) 为根时以 (u) 为根的子树的大小,(Fa_{root}(u)) 表示以 (root) 为根时 (u) 的父亲。那么(dp[u][v]=max(dp[u][Fa_u(v)],dp[Fa_v(u)][v])+Size_u(v) imes Size_v(u)) 。对于(Size_{root}(u)) 和 (Fa_{root}(u)),只要从每个点开始跑一遍DFS预处理即可,对于 (dp[u][v]) 记忆化搜索即可。时间复杂度 (O(n^2))。
Code
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
#include <map>
using namespace std;
#define RG register int
#define LL long long
template<typename elemType>
inline void Read(elemType &T){
elemType X=0,w=0; char ch=0;
while(!isdigit(ch)) {w|=ch=='-';ch=getchar();}
while(isdigit(ch)) X=(X<<3)+(X<<1)+(ch^48),ch=getchar();
T=(w?-X:X);
}
struct edge{int Next,to;};
edge G[6010];
int head[3010],Fa[3010][3010];
LL Size[3010][3010],dp[3010][3010];
int N,cnt=2;
LL Ans=0;
inline void Add_Edge(int u,int v){
G[cnt].to=v;
G[cnt].Next=head[u];
head[u]=cnt++;
}
void DFS(int u,int fa,int root){
Size[root][u]=1;
for(int i=head[u];i;i=G[i].Next){
int v=G[i].to;
if(v==fa) continue;
Fa[root][v]=u;
DFS(v,u,root);
Size[root][u]+=Size[root][v];
}
return;
}
LL DP(int u,int v){
if(u==v) return 0;
if(dp[u][v]) return dp[u][v];
return dp[u][v]=max(DP(u,Fa[u][v]),DP(Fa[v][u],v))+Size[u][v]*Size[v][u];
}
int main(){
Read(N);
for(RG i=1;i<=N-1;++i){
int u,v;
Read(u);Read(v);
Add_Edge(u,v);
Add_Edge(v,u);
}
for(RG i=1;i<=N;++i)
DFS(i,0,i);
for(RG u=1;u<=N;++u)
for(RG v=1;v<=N;++v)
Ans=max(Ans,DP(u,v));
printf("%I64d
",Ans);
return 0;
}