【POI每日题解 #8】DYN-Dynamite

你问蒟蒻为什么一天写两篇每日题解?

难道每日坚果你不能一天吃两包吗?

题目链接

…这道题第一反应就是二分答案【太明显了

枚举答案 就那个“关键节点到这些点中距离的最小值的最大值”【蒟蒻读了好几遍……

若枚举到mid 则判定答案为mid时,覆盖所有特殊点的最少点数能否不超过m

这很点分治

对于一个子树 我们要处理到它里面没有没被覆盖的点

或者有到该子树根距离小于mid的【它可以放在以后解决

那什么时候要选点呢?

自然是上面两个条件都不满足的时候

扫描二维码关注公众号,回复: 1771272 查看本文章

也就是离子树根最远的未被覆盖特殊点到子树根的距离等于mid 【注意边权为一,大于就来不及了

所以对每棵子树存储它未被处理的最远特殊点的距离

注意到一个节点连接的两棵子树可以互相覆盖

并且覆盖所经过的路径必然经过当前节点

因此 记录到每个根节点距离最近的已选点的距离

至此 维护两个值 点分治得以完成

蒟蒻一开始没想到能A这道题 随便一写一交【当然这习惯很不好

60了【facepalm  稍微debug下就A了……

但以后还是不要这么干…… 以此为戒

注意 对于1(根节点) 要进行特判

因为此时按点分治 到根节点距离小于mid的特殊点仍被保留

 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 }
check

猜你喜欢

转载自www.cnblogs.com/hjmmm/p/9232354.html