题解:P13680 [IAMOI R2] 未送出的花
树形 DP,时间复杂度 \(O(n^2)\),主要解答一些细节和疑惑,篇幅看起来长了点但是只是详细了一点而已。
方案中节点 \(u\) 的盛开度为 \(val_u\)。
性质 1:最优情况下,所有节点 \(u\) 的任意祖先盛开度都比 \(u\) 的盛开度要大。
证明:假设 \(a\) 是 \(b\) 的若干级祖先,且 \(val_a < val_b\),并且考虑 \(a\to b\) 路径上任意一节点 \(v\),如果交换 \(val_a,val_b\) 则会使得对于点 \(v\) 能取到的中位数可能变大,答案一定是不劣的。
考虑通过性质 1 对问题进行转化,则对于深度为 \(dep_u\) 的节点 \(u\) 取到的中位数一定是在其祖先链上第 \(\lceil \frac{dep_u}{2}\rceil\) 个点(不妨令其为 \(p\))上的 \(val_p\)。对于每个 \(p\) 我们统计它被多少 \(u\) 选中,记为 \(cnt_p\)。
性质 2:所有被选中的点 \(p\) 构成一个包含根节点 \(1\) 的联通块。
证明:考虑一个点 \(u\) 如果能选中一个点 \(p\),则说明该点的父亲也会选中一个在 \(1\to p\) 路径上的节点,\(1\to u\) 上所有节点选择的节点就能够覆盖 \(1\to p\) 上的所有节点。考虑树中所有叶子节点 \(u\),它到根的链上 \(1\to p\) 这一部分就是被选择的节点,所有 \(1\to p\) 的链重合使得 \(1\) 能够到达联通块内所有节点。
那么现在问题就变成了:
给定一个 \(k\),求选择 \(num\) 个节点构成包含 \(1\) 的联通块,其权值 \(\sum cnt\geq k\),且使 \(num\) 最小化(由于只需要填 \(num\) 个点,答案即为 \(n-num+1\))
有一个简单的思路,维护一个关于 \(cnt_u\) 的大根堆,先把 \(1\) 入堆,然后每次取出堆顶,将目前总共能覆盖的节点数量加上 \(cnt_u\) 贪心地将相连节点都入堆。这样显然是错误的。
性质 3:在 \(k=1\dots n\) 的情况中,\(k=a-1\) 对于 \(k=a\) 不具可差分性。
证明:容易发现,做 \(k=a-1\) 是存在后效性的,这也是为什么我们不能使用大根堆直接做的原因。考虑一个 hack,存在一个节点 \(u\) 其 \(val\) 具有极大值,但是其父亲的 \(val_{fa}\) 具有极小值,那么在做大根堆的时候我们肯定会先入堆若干个与 \(fa\) 同级的且 \(val\) 比 \(fa\) 大的节点,这样会使得需要覆盖的节点数大幅增加,但是如果直接先取 \(fa\) 再取 \(u\) 就可以只增加 \(2\) 个需要节点然后解决后续的问题。
考虑正解,虽然连通块形态是不可差分的,但是对于每个 \(k\) 我们选到的联通块,其大小一定是随着 \(k\) 的需求增加而不降的,相应的选到的联通块大小 \(j\) 也一定对应着一段覆盖的 \(k\) 的区间。不妨令 \(dp_{i,j}\) 表示以 \(i\) 为根的子树中选了包含 \(i\) 的联通块大小为 \(j\) 所能取到最大的 \(\sum cnt\),初始化 \(dp_{u,1}=cnt_u\),转移是 \(O(n^3)\) 的,利用 \(siz_u\) 限制可以做到 \(O(n^2)\),令 \(v\) 为 \(u\) 的儿子,则 \(dp_{u,sum}=\max \sum dp_{v,b_v}(\sum b_v=sum)\),转移是树形 DP 的基础内容,这里不做展开。
最后 \(dp_{1,j}\) 可以覆盖 \([dp_{1,j-1}+1,dp_{1,j}]\) 上所有 \(k\) 的值,相应计算即可。实际上大部分情况做树形 DP 时只需要遍历约一半的节点,因为有用的(\(cnt_u>0\))的节点也差不多是这个数,当然要是构造出一个菊花那就是另一回事了,时间还是比较优秀的。
#include<bits/stdc++.h>
using namespace std;
const int N=1e4+5;
vector<int>G[N];
int n,cnt[N],rcnt;
int stk[N],tp;
int dp[N][N],siz[N];
int ans[N];
void dfs(int u,int fa){
stk[++tp]=u;
cnt[stk[(tp+1)/2]]++;
for(int v:G[u]){
if(v==fa)continue;
dfs(v,u);
}
stk[tp--]=0;
if(u)rcnt++;
}
void dfs1(int u,int fa){
if(!cnt[u])return ;
siz[u]=1;dp[u][0]=0;
dp[u][1]=cnt[u];
for(int i=2;i<=rcnt;i++)
dp[u][i]=0;
for(int v:G[u]){
if(v==fa)continue;
if(!cnt[v])continue;
dfs1(v,u);
for(int i=siz[u];i>=1;i--)
for(int j=siz[v];j>=0;j--)
dp[u][i+j]=max(dp[u][i+j],dp[u][i]+dp[v][j]);
siz[u]+=siz[v];
}
}
int main(){
ios::sync_with_stdio(0);
cin.tie(0);cout.tie(0);
int T;cin>>T;
while(T--){
cin>>n;rcnt=0;
for(int i=1;i<=n;i++)
G[i].clear(),
cnt[i]=0;
for(int i=1;i<n;i++){
int u,v;cin>>u>>v;
G[u].push_back(v);
G[v].push_back(u);
}
dfs(1,0);
dfs1(1,0);
int now=0;
for(int i=1;i<=n;i++)
while(now<dp[1][i])ans[++now]=n-i+1;
for(int i=1;i<=n;i++)
cout<<ans[i]<<' ';
cout<<'\n';
}
return 0;
}

浙公网安备 33010602011771号