模板题引入
先来看一道模板题,CF上的。
这题的意思是给定一棵有 n n n个节点的树,树上有一些关键点( k e y key key)。接下来有 q q q组询问,每次给出 k i k_i ki个 k e y key key,要求删去一些点,使得这些 k e y key key不相连。要求删去的最少的点数。
模板题解析
第一眼看到这题,先想到的肯定是树形 d p dp dp。毕竟是在树上嘛。但是接下来看了一眼范围 1 ≤ n ≤ 100000 1\le n\le 100000 1≤n≤100000,而且 1 ≤ q ≤ 100000 1\le q\le 100000 1≤q≤100000。如果对于每个 q q q都跑一次完整的树,那么显然, O ( n ∗ q ) O(n*q) O(n∗q)一算就会 T L E TLE TLE。
那么我们可以先不考虑这个,先想怎么 d p dp dp。很简单,运用贪心,分类。
如果当前节点是关键点,那么查询它是否有子儿子是关键点,如果有,那么显然连向这个子节点的链上需要被截断,否则就不用。
如果不是关键点,那么如果子树中有关键点并且多于 2 2 2个,那么显然,把当前节点删掉会最优,如果只有一个,那么留到后面和其他子树中的关键点分割更优。
因此,设当前节点是 x x x,它的儿子是 s o n son son,定义 d p [ i ] dp[i] dp[i]表示以 i i i为根的子树,使得所有的 k e y key key都不连通的最小删点个数, s i z [ i ] siz[i] siz[i]表示以 i i i为根的子树里 k e y key key的个数。则有:
i f ( x 是 k e y ) if(x是key) if(x是key)
d p [ x ] + = d p [ s o n ] ; \qquad dp[x]+=dp[son]; dp[x]+=dp[son];
i f ( s i z [ s o n ] ) a n s [ x ] + + ; \qquad\qquad if(siz[son]) ans[x]++; if(siz[son])ans[x]++;
e l s e else else
a n s [ x ] + = a n s [ s o n ] ; \qquad ans[x]+=ans[son]; ans[x]+=ans[son];
s i z [ x ] + = s i z [ s o n ] ; \qquad siz[x]+=siz[son]; siz[x]+=siz[son];
\qquad 在遍历完子节点后
i f ( s i z [ x ] > 1 ) \qquad if(siz[x]>1) if(siz[x]>1)
s i z [ x ] = 0 ; \qquad\qquad siz[x]=0; siz[x]=0;
a n s [ x ] + + ; \qquad\qquad ans[x]++;