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

时间:2023-08-06 22:36:05
【POI每日题解 #8】DYN-Dynamite

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

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

题目链接

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

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

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

嗯 这很点分治

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

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

那什么时候要选点呢?

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

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

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

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

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

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

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

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

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

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

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

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

 void dfs(int x, int fa){
d1[x] = sp[x] ? : -N; d2[x] = N;
for(int i = head[x]; i != -; i = edge[i].next){
int vv = edge[i].v;
if(vv == fa) continue;
dfs(vv, x);
if(d1[vv] != -N) d1[x] = max(d1[x], d1[vv] + );
d2[x] = min(d2[x], d2[vv] + );
}
if(d1[x] + d2[x] <= mid) d1[x] = -N;//!!!
if(d1[x] == mid){
tot++; d1[x] = -N; d2[x] = ;
}
if(sp[x] && d2[x] > mid)
d1[x] = max(d1[x], ); //!!!
} inline bool check(){
tot = ;
dfs(, );
if(d1[] + d2[] > mid) tot++;//!!!
return tot <= m;
}

check