转载一个大佬的题解:
主要考察二分查找、树上倍增、贪心、“树上前缀和”。
题目是一颗树,要求将一条边的权值变为0,使得所有运输计划的最大时间最小。
直觉告诉我们,这是一个树上倍增的题目,但是它却不像前几年的 Day2T3 开车旅行那样纯倍增,或许更像疫情控制一些,倍增只是辅助算法,还需要配合其他算法。
由于要使所有运输计划的最大时间最小,不难想到二分答案的方法。
使C(t)表示是否可以改造一条边,使得改造之后所有运输计划中最长的时间不大于t。这是惯用伎俩,用二分的的话,我们就可以确定一个变量t,正因为有了这个t,我们才能有的放矢的进行贪心或是干别的。
如何判断C(t)呢?在开始的时候用倍增预处理出所有计划的时间,如果小于等于t,就可以忽略,如果大于t,那么就要考虑在其路径上改造一条边。
由于所有时间大于t的计划都要改造一条边,问题就变为了求所有时间大于t的计划的路径交集,改造其中一条最大的边,看看去掉这条边之后,是否可以满足条件。
问题来了,如何求交集呢?
这里给出两种方法,一种是模拟求交集。一种是利用树上前缀和求交集。如果设total为超出时间t的方案数量,边e?i??经过的次数cnt?i??。对于每个超出时间t的方案,将其路径中边的cnt加1。最后,所有cnti=totalcnt?i??的边就是我们要求的的交集。
然而每次给每条边加一肯定是不现实的,所以我们要想出一个高效的方法,来维护边被经过的次数。
这个方法像极了2012年NOIP的借教室,不过是树上的版本。我们先看看借教室的怎么处理区间加减的。
如果要对一段连续区间[a,b)同时加上一个值,只需在开始处加上这个值,在结束后减去这个值,维护前缀和就行了。看上去应该是这样的:若初始都是0,让连续区间[a,b)同时加上一个值m之后,前缀和 即为元素i的值。下面是前缀和:
如果有多组加减,也不会冲突。
同样的,在树上,我们用s?i??来表示顶点i到其父亲的这条边被经过的次数,v?i??用于记录顶点信息。
对于每个点对(a,b),我们将v?a??+1,