CF1830D Mex Tree
发现一个巨大无比爆炸重要的性质。树上路径 MEX 只有 0,1,2 三种情况/dy。
很自然会想交替染色。这样答案最劣大概为 \(n(n+1)-n\)。
想了会交替染色为何不对,发现对于单点填 0 会有 1 的贡献,而填 1 没有贡献。所有交替染色只能保证长度 \(\ge 2\) 的路径的权值和最大。
最优化可以考虑上下界。先钦定答案为上界 \(n(n+1)\),即每条路径 MEX 都为 2。虽然显然取不到。
答案为 \(n(n+1)-c1-2\cdot c0\) 其中 \(c1\) 为 MEX 为 1 的路径数,\(c0\) 为 MEX 为 0 的路径数,发现 \(c0,c1\) 与 \(0,1\) 的极大连通块有关,一个大小为 \(siz\) 的极大连通块可以贡献 \(\frac{siz(siz+1)}{2}\) 条路径,现在就是要考虑最小化 \(c1+2\cdot c0\)。于是设计状态 \(f_{u,i,0/1}\) 表示以 \(u\) 为根的子树,\(u\) 在大小为 \(i\) 的 \(0/1\) 的极大连通块中,这个状态显然就是背包:
\(f'_{u,k,0}=\max\{f_{u,i,0}+f_{v,k-i,0}+ij,f_{u,k,0}+f_{v,j,1}\}\)。
\(f'_{u,k,1}=\max\{f_{u,i,1}+f_{v,k-i,1}+2ij,f_{u,k,1}+f_{v,j,0}\}\)。
树上背包复杂度是 \(O(n,k)\) 的,其中 \(k\) 是背包大小,所以这里复杂度是 \(O(n^2)\) 的。发现复杂度有点炸。
而背包显然没有什么好的优化方式,所以要不就优化背包大小,要不就换个思路。那既然都讲了那么多了换个思路就不太可能了/oh。
交替染色能得到 \(n(n+1)-n\)。也就是说只要答案 \(<n(n+1)-n\) 的就是无用答案了,一定有比其更优的答案。\(c1+2\cdot c0\le n\)。所以一个同色极大连通块的大小不应该超过 \(\sqrt{n}\),要不然根据其贡献显然不优。
背包大小减少至 \(\sqrt{n}\),复杂度 \(O(n\sqrt n)\)。
哦还有空间会炸,于是每个节点转移完就释放掉其状态的 vector 的空间。这样就是 \(O(n)\) 的空间复杂度。
#include<bits/stdc++.h>
#define fin(x) freopen(#x".in","r",stdin)
#define fout(x) freopen(#x".out","w",stdout)
#define fr(x) fin(x),fout(x);
#define Fr(x,y) fin(x),fout(y)
#define INPUT(_1,_2,FILE,...) FILE
#define IO(...) INPUT(__VA_ARGS__,Fr,fr)(__VA_ARGS__)
using namespace std;
#define mp make_pair
#define pii pair<int,int>
#define fi first
#define se second
#define pb push_back
#define cfast ios::sync_with_stdio(false);cin.tie(0),cout.tie(0)
#define ll long long
#define ull unsigned long long
#define intz(x,y) memset((x),(y),sizeof((x)))
char *p1,*p2,buf[100000];
#define nc() (p1==p2 && (p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++)
#define tup(x) array<int,(x)>
inline ll read(){
ll x=0,f=1;char ch=nc();
while(ch<48||ch>57){if(ch=='-')f=-1;ch=nc();}
while(ch>=48&&ch<=57)x=x*10+ch-48,ch=nc();
return x*f;
}
//void write(int x){cout<<x<<' ';}
//void write(pii x){cout<<"P("<<x.fi<<','<<x.se<<")\n";}
//void write(vector<auto>x){for(auto i:x)write(i);cout<<'\n';}
//void write(auto *a,int l,int r){for(int i=l;i<=r;i++)write(a[i]);cout<<'\n';}
inline ll lowbit(ll x){return x&-x;}
inline int pcount(ll x){
for(int i=0,res=0;;res+=(x>>i)&1,i++)
if(i>60)return res;
}
//struct mt{
// ll v;
// mt(){v=0;}
// mt(int x){this->v=x;}
// inline mt operator+(mt x){return {(v+x.v)%mod};}
// inline mt operator-(mt x){return {(v+mod-x.v)%mod};}
// inline mt operator*(mt x){return {1ll*v*x.v%mod};}
//};
//mt qp(mt x,int y){mt res(1);for(;y;x=x*x,y>>=1)if(y&1)res=res*x;return res;}
const int N=2e5+5;
#define int ll
vector<int>e[N],f[N][2],tmp[2];
int n,B,siz[N];
void dfs(int u,int fa){
siz[u]=1;
for(int i:{0,1})
f[u][i].resize(2),
f[u][i][0]=1e9,
f[u][i][1]=(i==1?2:1);
for(int v:e[u])if(v^fa){
dfs(v,u);
tmp[0].clear(),tmp[1].clear();
for(int i:{0,1})
tmp[i].resize(min(B+1,siz[u]+siz[v]+1));
for(int p:{0,1})
for(int &i:tmp[p])i=1e9;
for(int i=0;i<=min(siz[u],B);i++)
for(int j=0;j<=min(siz[v],B);j++){
if(i+j<B)
tmp[0][i+j]=min(tmp[0][i+j],f[u][0][i]+f[v][0][j]+i*j),
tmp[1][i+j]=min(tmp[1][i+j],f[u][1][i]+f[v][1][j]+2*i*j);
tmp[0][i]=min(tmp[0][i],f[u][0][i]+f[v][1][j]),
tmp[1][i]=min(tmp[1][i],f[u][1][i]+f[v][0][j]);
}
swap(f[u][0],tmp[0]),swap(f[u][1],tmp[1]);
tmp[0].clear(),tmp[1].clear();
for(int i:{0,1})
f[v][i].clear(),
f[v][i].shrink_to_fit();
siz[u]+=siz[v];
}
}
inline void UesugiErii(){
cin>>n,B=sqrt(n)+5;
for(int i=1,u,v;i<n;i++)
cin>>u>>v,e[u].pb(v),e[v].pb(u);
dfs(1,0);int ans=1e9;
for(int p:{0,1})
for(int it:f[1][p])
ans=min(ans,it);
cout<<n*(n+1)-ans<<'\n';
for(int i=1;i<=n;i++){
e[i].clear();
for(int j:{0,1})
f[i][j].clear();
}
}
signed main(){
//IO();
cfast;
int _=1;cin>>_;
for(;_;_--)UesugiErii();
return 0;
}

浙公网安备 33010602011771号