CF1830D 题解
honglan0301 · · 题解
题目分析
首先注意到
但是这样贪并不总是最优的,比如造一个在一条边两段挂分别挂很多条边的树,此时最优解是把中间两个点都染成
然后可以换个角度从反面想,发现当且仅当一条路径只经过一种颜色的点时其
那么考虑
于是做完了,下面补充一些应该是前置知识的东西。考虑时间复杂度,如上的树上背包根据
-
当
size_u>\sqrt n,size_v>\sqrt n 时:这样的合并至多进行O(\frac{n}{\sqrt n})=O(\sqrt n) 次,故时间复杂度O(n\sqrt n) 。 -
当
size_u<\sqrt n,size_v<\sqrt n 时:这等价于在每个size<\sqrt n 的子树上做无限制的背包,容易发现找出每个size<\sqrt n 的极大子树后时间复杂度就是O(\sum size^2)\leq O(\max size\times \sum size)=O(n\sqrt n) 。 -
当
size_u<\sqrt n,size_v>\sqrt n 时:注意到每个点至多有一个祖先u 会进行这样的合并,且每个点u 至多进行一次,故时间复杂度O(\sum size_u\times \sqrt n)=O(n\sqrt n) 。 -
当
size_u>\sqrt n,size_v<\sqrt n 时:注意到每个点至多有一个祖先v 会进行这样的合并,且每个v 本来就只会合并一次,故时间复杂度O(\sum size_v\times \sqrt n)=O(n\sqrt n) 。
再考虑空间复杂度,直接开满显然是
感觉还不错,启发性在于对
代码
/*
author: PEKKA_l
*/
#include <iostream>
#include <cstring>
#include <algorithm>
#include <vector>
using namespace std;
#define pb push_back
#define B 785ll
#define INF 100000000000
#define int long long
int t,n,u,v,sz[200005],g[2][805];
vector <int> e[200005],dp[200005][2];
void dfs(int x,int fat)
{
sz[x]=1; dp[x][0].pb(INF); dp[x][1].pb(INF); dp[x][0].pb(1); dp[x][1].pb(2);
for(auto i:e[x])
{
if(i==fat) continue; dfs(i,x);
int min0=INF,min1=INF;
for(int j=1;j<=min(B,sz[i]);j++) min0=min(min0,dp[i][0][j]),min1=min(min1,dp[i][1][j]);
for(int j=1;j<=min(B,sz[x]);j++) g[0][j]=dp[x][0][j],g[1][j]=dp[x][1][j],dp[x][0][j]=dp[x][1][j]=INF;
for(int j=min(B,sz[x])+1;j<=min(B,sz[x]+sz[i]);j++) dp[x][0].pb(INF),dp[x][1].pb(INF);
for(int j=1;j<=min(B,sz[x]+sz[i]);j++)
{
for(int k=max(1ll,j-min(B,sz[x]));k<=min(j-1,min(B,sz[i]));k++)
{
dp[x][0][j]=min(dp[x][0][j],dp[i][0][k]+g[0][j-k]+j*k-k*k);
dp[x][1][j]=min(dp[x][1][j],dp[i][1][k]+g[1][j-k]+2*j*k-2*k*k);
}
}
for(int j=1;j<=min(B,sz[x]);j++)
{
dp[x][0][j]=min(dp[x][0][j],g[0][j]+min1); dp[x][1][j]=min(dp[x][1][j],g[1][j]+min0);
}
sz[x]+=sz[i]; dp[i][0].clear(); dp[i][0].shrink_to_fit(); dp[i][1].clear(); dp[i][1].shrink_to_fit();//
}
}
signed main()
{
cin>>t;
while(t--)
{
cin>>n; for(int i=1;i<=n;i++) e[i].clear(),dp[i][0].clear(),dp[i][1].clear();
for(int i=1;i<=n-1;i++) {cin>>u>>v; e[u].pb(v); e[v].pb(u);} dfs(1,1);
int nans=INF; for(int i=1;i<=min(B,sz[1]);i++) nans=min(nans,min(dp[1][0][i],dp[1][1][i]));
cout<<n*(n+1)-nans<<endl;//
}
}