[CF 468 Div.1D]Valid Sets

题意

一个(n)个节点的树,边有边权,求一个字典序最小的排列(p),令(sum_{i=1}^nlimits dis(i,p_i))最大

分析

我们考虑(dis(i,p_i))实际上可以拆成三段:(sum dep(i)+dep(p_i)-2dep_{lca(i,p_i)}=2sum dep_i-2sum dep_{lca(i,p_i)})

考虑选重心作为根,那么就可以平衡地配对起来,让不同子树之间的配对,使得后面那一项变成(0),那么整个式子就最大。那么这时这个答案就很容算出来,但是怎么让字典序最小呢?

考虑我们把root删掉的话,那么我们要最小就需要满足两个需求:

  • 每次给某个(i)(p_i)选一个最小的(j),同时这个(j)还不能在和(i)同一棵子树里面
  • 不能在某个时刻对于某个(i)我们不能选点匹配了,也就是我们对于某些子树我们可能需要优先考虑,这时需要优先满足贡献最大的需求

先考虑“合法解”满足的条件。什么时候我们需要优先考虑某些子树呢?我们考虑目前已经确定了排列的前(i)项,一个子树里面有(t)个大于(i)的节点(肯定都没配对),这个子树里面还有(x)个没被配对的节点(没被前面的某个(p)选中),那么实际配对节点一共有(n-i)个,但是不能配对同一棵子树里面的,所以实际可以配对的只有(n-i-x)个,还未配对的(t)个节点必须有配对。

所以当(t+xleq n-i)的时候才行。然而如果一棵子树出现(t+x=n-i)的时候就很关键了。因为(i)在一直变大,右边一直在变小,如果左边不能一起变小的话就完蛋了。那么要么就是(t)要么就是(x)能够减(1),那么这个等式其实就会一直满足了!

我们考虑用set维护下所有子树的(t+x),然后考虑有没有满足等式的子树,然后如果有,而且如果(i)在这棵子树里就照做,反之必须要找一个(j)在这棵子树里。剩下的情况上面已经讨论过了。

对于找最小的贪心,可以用线段树,同一棵子树里面按照编号放进一个区间里面,每次指针往后移即可,而对于根可以和任意节点(包括自己)配对,需要特殊考虑。

原文地址:https://www.cnblogs.com/wendavid/p/9101999.html