[AGC008F] Black Radius
记 \(S(u,d)\) 表示与 \(u\) 的距离不大于 \(d\) 的点构成的点集。
为了方便后面的讨论,先加入全集的贡献 \(1\)。
当所有点均可选时,考虑如何不重的计算点集,
有些题解写的是: \(\forall u\not=v , S(u,d_u)=S(v,d_v) \rightarrow d_u \not= d_v\),个人感觉是错的
结论应该是:相同的 \(S(u,d)\) 中 \(d\) 最小的 \(u\) 唯一。
证明:
to be continued...
那么可以在相同点集时在最小的 \(d\) 对应的点 \(u\) 计算答案。
记 \(mx1_u\) 表示离 \(u\) 最远的点(最长链),显然有 \(d_u < mx1_u\) (不能覆盖整棵树)
其次,若有 \(S(u,d)=S(v,d-1)\) , 说明 \(u\) 的其它子树的深度 \(\le d-3\)
也就是说,对于任意 \(v\) 都有 \(d \le 1+\max_{w \not= v} mx1_w+1\),当 \(v\) 所在子树即为最深子树时限制最紧,为次长链长度,记为 \(mx2_u\)
最终得到: \(d_u \le \min(mx1_u-1,mx2_u+1)\)
现在考虑部分点不可选,我们仍在 \(d\) 最小的点计算答案(即使 \(u\) 不可选)
现在需要保证 \(S(u,d_u)\) 可以对应另一个 \(S(p,d_p)\) ,其中 \(p\) 是可选的。
充要条件是: \(S(u,d_u)\) 包含 \(u\) 的包含 \(p\) 的子树中的所有节点。
证明:
- 充分性
反证,若存在子树 \(t\) 没有被包含,显然 \(d_3>d_1\)
可知 \(S(u,d_2+d_3)=S(Z,d3)\) , 矛盾- 必要性
\(d_p\) 取 \(d_u-1\) 便是一个合法的解。
可以使用换根 dp 解决。
#include <bits/stdc++.h>
using namespace std;
#define ll long long
const int MAXN = 2e5 , Inf = 0x3f3f3f3f;
int n; char s[ MAXN + 5 ];
vector< int > Graph[ MAXN + 5 ];
ll ans;
int siz[ MAXN + 5 ] , d[ MAXN + 5 ]; //覆盖关键点的子树的最小 d
int mx1[ MAXN + 5 ] , mx2[ MAXN + 5 ]; //最长链,次长链
void dfs1( int u , int fa ) {
if( s[ u ] == '1' ) d[ u ] = 0 , siz[ u ] = 1;
else d[ u ] = Inf;
for( int v : Graph[ u ] ) if( v != fa ) {
dfs1( v , u ); siz[ u ] += siz[ v ];
if( mx1[ u ] < mx1[ v ] + 1 ) mx2[ u ] = mx1[ u ] , mx1[ u ] = mx1[ v ] + 1;
else if( mx2[ u ] < mx1[ v ] + 1 ) mx2[ u ] = mx1[ v ] + 1;
if( siz[ v ] ) d[ u ] = min( d[ u ] , mx1[ v ] + 1 );
}
}
void dfs2( int u , int fa ) {
int up = min( mx2[ u ] + 1 , mx1[ u ] - 1 );
if( d[ u ] <= up ) ans += up - d[ u ] + 1;
for( int v : Graph[ u ] ) if( v != fa ) {
int lu = ( mx1[ u ] == mx1[ v ] + 1 ) ? mx2[ u ] + 1 : mx1[ u ] + 1;
if( mx1[ v ] < lu ) mx2[ v ] = mx1[ v ] , mx1[ v ] = lu;
else if( mx2[ v ] < lu ) mx2[ v ] = lu;
if( siz[ 1 ] - siz[ v ] ) d[ v ] = min( d[ v ] , lu );
dfs2( v , u );
}
}
int main( ) {
// freopen("fire.in","r",stdin);
// freopen("fire.out","w",stdout);
scanf("%d",&n);
for( int i = 1 , u , v ; i < n ; i ++ ) {
scanf("%d %d",&u,&v);
Graph[ u ].push_back( v );
Graph[ v ].push_back( u );
}
scanf("%s", s + 1 );
dfs1( 1 , 0 ); dfs2( 1 , 0 );
printf("%lld\n", 1 + ans );
return 0;
}