【Codeforces Round #268(Div 1)】Tree

Description

有一棵树, d(u,v) 表示 u v 之间最短距离。
现在要求一个排列 pi ,使得 ni=1d(i,pi) 最大,同时满足最大时字典序最小。

Solution

对于一条边,我们肯定希望它被计算尽量多次,若左右端点连出去的节点个数分别为 x , y ,那么该边的最大贡献为 val×min(x,y)×2 ,于是选择重心来构造恰好能满足(如下)。

先把式子写出来:

i=1nd(i,pi)=i=1n(depi+deppi2deplca(i,pi))=2i=1ndepii=1n2deplca(i,pi)

选定一个根,每对点不能出现在根直接连下去的同一棵子树中。
对于根直接连向的每棵子树,设大小为 k ,子树内的点可以和子树外的 nk 个点匹配,同时这 k 个点都要被匹配,那么 knk kn2 。那么选择树的重心为根就能满足。

于是我们抛开权值,只用找字典序最小的排列。

对于当前将要匹配 i ,要找到最小的 pi ,同时满足不同根直属子树。设当前子树有 x 个未匹配的(即编号大于 i 的个数),以及有 y 个未被匹配的(在这棵子树中不出现在已确定 pi 中的编号),那么满足 xni+1y ,即 x+yni+1 。对于一棵子树满足 x+y=ni+1 ,那么当 i+1 时, x y 要减 1 。此时分两种情况:

  1. i 在这棵子树内,那么可以直接和子树外的匹配,使得 x1
  2. i 不在这棵子树内,那么必须选择这棵子树内的匹配,使得 y1

若当前没有满足等式的情况,直接选择与 i 不同子树匹配即可。
(对于每次匹配,选择编号最小的)
至于重心,当满足等式时,那么必须选择那棵子树,如不满足,则匹配最小编号(可以匹配自己)。

于是可以用线段树维护,对每个子树开一个位置,存储 x y ,以及被匹配了多少个。

猜你喜欢

转载自blog.csdn.net/sadnohappy/article/details/78756125