题解 CF1338D 【Nested Rubber Bands】
评分还没出,目测难度在
题意
给定一棵
你需要将每一个节点画成一个二维平面上闭合几何图形,满足如果
我们定义一个序列
求好的序列最长可以是多少。
(题面翻译是我写的)
题解
性质1
如果两个点之间有边相连,那么这两个点对应的图形不可能互相包含。
这一点是显然的。
性质2
对于一个序列
证明:
假设我们已经画出来了一个连通子树,我们需要画出来其它所有的点。
在这个连通子树内任意取一个点当根进行 bfs,如果当前点
继续画下去就可以得到整棵树。
性质3
对于任意一个点
证明:
考虑反证法,设
考虑
接下来考虑
思路
我们考虑不违反上述三条性质的序列。可以发现,这个序列一定满足存在一条链,使得所有点要么在链上要么和链直接相连。因为对任意一个点来说,不和它直接相连的序列中的点至多位于它的两棵子树内。大家感性理解一下。
这样我们就有了一个暴力思路:枚举一条链,把这条链以及和它相邻的点拿出来,求一个最大独立集。
这个算法显然会 TLE,我们考虑用树形 DP 的思想。
对于一个点
再设
树形 DP 的经典模型:
初始别忘了让
在转移的过程中随时更新答案:
时间复杂度
代码
比赛的时候 DP 状态略微有些不同,为了写这篇题解专门又改了改:
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
struct Edge
{
int to;
int nxt;
}e[200005];
int n,m,edgenum,head[100005],dep[100005],pa[100005],d[100005],ans;
int f[100005][2];
void add(int u,int v)
{
e[++edgenum].to=v;
e[edgenum].nxt=head[u];
head[u]=edgenum;
}
void dfs(int node)
{
dep[node]=dep[pa[node]]+1;
f[node][0]=0,f[node][1]=1;
for(int hd=head[node];hd;hd=e[hd].nxt)
{
int to=e[hd].to;
if(to==pa[node])continue;
pa[to]=node;
dfs(to);
ans=max(ans,f[node][0]+f[to][0]);
ans=max(ans,f[node][0]+f[to][1]);
ans=max(ans,f[node][1]+f[to][0]);
f[node][0]=max(f[node][0],f[to][1]+d[node]-2);
f[node][0]=max(f[node][0],f[to][0]+d[node]-2);
f[node][1]=max(f[node][1],f[to][0]+1);
}
ans=max(ans,f[node][1]);
}
int main()
{
scanf("%d",&n);
for(int i=1;i<n;i++)
{
int u,v;
scanf("%d%d",&u,&v);
add(u,v);
add(v,u);
d[u]++,d[v]++;
}
dfs(1);
printf("%d\n",ans);
return 0;
}
赛时提交记录:76398535