【POI每日题解 #8】DYN-Dynamite
你问蒟蒻为什么一天写两篇每日题解?
难道每日坚果你不能一天吃两包吗?
哇…这道题第一反应就是二分答案【太明显了
枚举答案 就那个“关键节点到这些点中距离的最小值的最大值”【蒟蒻读了好几遍……
若枚举到mid 则判定答案为mid时,覆盖所有特殊点的最少点数能否不超过m
嗯 这很点分治
对于一个子树 我们要处理到它里面没有没被覆盖的点
或者有到该子树根距离小于mid的【它可以放在以后解决
那什么时候要选点呢?
自然是上面两个条件都不满足的时候
也就是离子树根最远的未被覆盖特殊点到子树根的距离等于mid 【注意边权为一,大于就来不及了
所以对每棵子树存储它未被处理的最远特殊点的距离
注意到一个节点连接的两棵子树可以互相覆盖
并且覆盖所经过的路径必然经过当前节点
因此 记录到每个根节点距离最近的已选点的距离
至此 维护两个值 点分治得以完成
蒟蒻一开始没想到能A这道题 随便一写一交【当然这习惯很不好
就60了【facepalm 稍微debug下就A了……
但以后还是不要这么干…… 以此为戒
注意 对于1(根节点) 要进行特判
因为此时按点分治 到根节点距离小于mid的特殊点仍被保留
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 void dfs(int x, int fa){ 2 d1[x] = sp[x] ? 0 : -N; d2[x] = N; 3 for(int i = head[x]; i != -1; i = edge[i].next){ 4 int vv = edge[i].v; 5 if(vv == fa) continue; 6 dfs(vv, x); 7 if(d1[vv] != -N) d1[x] = max(d1[x], d1[vv] + 1); 8 d2[x] = min(d2[x], d2[vv] + 1); 9 } 10 if(d1[x] + d2[x] <= mid) d1[x] = -N;//!!! 11 if(d1[x] == mid){ 12 tot++; d1[x] = -N; d2[x] = 0; 13 } 14 if(sp[x] && d2[x] > mid) 15 d1[x] = max(d1[x], 0); //!!! 16 } 17 18 inline bool check(){ 19 tot = 0; 20 dfs(1, 1); 21 if(d1[1] + d2[1] > mid) tot++;//!!! 22 return tot <= m; 23 }