题目链接
题目解法
路径上全
0
0
0 会使答案
−
1
-1
−1,全
1
1
1 会使答案
−
2
-2
−2
考虑估算答案的下界,一个优秀的方案是黑白染色
那么这时可以得到答案的下界为
n
(
n
+
1
)
−
2
n
n(n+1)-2n
n(n+1)−2n
然后我们就可以考虑暴力的
d
p
dp
dp 了
令
f
i
,
j
,
0
/
1
f_{i,j,0/1}
fi,j,0/1 为在
i
i
i 的子树中,
i
i
i 所在连通块大小为
j
j
j,颜色为
0
/
1
0/1
0/1 的方案数
考虑
j
j
j 的取值范围,因为我们得到了答案的下界,所以可知
j
≤
n
j\le \sqrt n
j≤n
直接树形
d
p
dp
dp 即可
时间复杂度
O
(
T
n
n
)
O(Tn\sqrt n)
O(Tnn),需要用
v
e
c
t
o
r
vector
vector 存数组,且及时释放
#include <bits/stdc++.h>
#define pb push_back
#define int long long
using namespace std;
const int N=200100,inf=1e18;
int n,B,siz[N];
int e[N<<1],ne[N<<1],h[N],idx;
vector<int> f[N][2];
inline int read(){
int FF=0,RR=1;
char ch=getchar();
for(;!isdigit(ch);ch=getchar()) if(ch=='-') RR=-1;
for(;isdigit(ch);ch=getchar()) FF=(FF<<1)+(FF<<3)+ch-48;
return FF*RR;
}
inline void chkmin(int &x,int y){ if(y<x) x=y;}
void dfs(int u,int fa){
f[u][0].pb(inf),f[u][0].pb(1),f[u][1].pb(inf),f[u][1].pb(2);
siz[u]=1;
for(int i=h[u];~i;i=ne[i]){
int v=e[i];if(v==fa) continue;
dfs(v,u);
int LIM=min(siz[u]+siz[v],B)+5;
vector<int> t[2];t[0].resize(LIM,inf),t[1].resize(LIM,inf);
for(int j=1;j<=min(siz[u],B);j++) for(int k=1;k<=min(siz[v],B);k++){
chkmin(t[0][j],f[u][0][j]+f[v][1][k]);
chkmin(t[1][j],f[u][1][j]+f[v][0][k]);
if(j+k<=B){
chkmin(t[0][j+k],f[u][0][j]+f[v][0][k]+j*k);
chkmin(t[1][j+k],f[u][1][j]+f[v][1][k]+j*k*2);
}
}
siz[u]+=siz[v];
f[u][0].resize(LIM);f[u][1].resize(LIM);
for(int j=0;j<LIM;j++) f[u][0][j]=t[0][j],f[u][1][j]=t[1][j];
t[0].clear(),t[0].shrink_to_fit();
t[1].clear(),t[1].shrink_to_fit();
f[v][0].clear(),f[v][0].shrink_to_fit();
f[v][1].clear(),f[v][1].shrink_to_fit();
}
}
void add(int x,int y){ e[idx]=y,ne[idx]=h[x],h[x]=idx++;}
void work(){
int n=read();
for(int i=1;i<=n;i++) h[i]=-1;idx=0;
for(int i=1;i<n;i++){
int x=read(),y=read();
add(x,y),add(y,x);
}
B=sqrt(n)+5;
dfs(1,-1);
int res=inf;
for(int i=1;i<=min(siz[1],B);i++) res=min(res,min(f[1][0][i],f[1][1][i]));
f[1][0].clear(),f[1][0].shrink_to_fit();
f[1][1].clear(),f[1][1].shrink_to_fit();
printf("%lld\n",n*(n+1)-res);
}
signed main(){
int T=read();
while(T--) work();
fprintf(stderr,"%d ms\n",int64_t(1e3*clock()/CLOCKS_PER_SEC));
return 0;
}