[CF 468 Div.1D]Valid Sets
题意
一个\(n\)个节点的树,边有边权,求一个字典序最小的排列\(p\),令\(\sum_{i=1}^n\limits dis(i,p_i)\)最大
分析
我们考虑\(dis(i,p_i)\)实际上可以拆成三段:\(\sum dep(i)+dep(p_i)-2dep_{lca(i,p_i)}=2\sum dep_i-2\sum 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+x\leq n-i\)的时候才行。然而如果一棵子树出现\(t+x=n-i\)的时候就很关键了。因为\(i\)在一直变大,右边一直在变小,如果左边不能一起变小的话就完蛋了。那么要么就是\(t\)要么就是\(x\)能够减\(1\),那么这个等式其实就会一直满足了!
我们考虑用set维护下所有子树的\(t+x\),然后考虑有没有满足等式的子树,然后如果有,而且如果\(i\)在这棵子树里就照做,反之必须要找一个\(j\)在这棵子树里。剩下的情况上面已经讨论过了。
对于找最小的贪心,可以用线段树,同一棵子树里面按照编号放进一个区间里面,每次指针往后移即可,而对于根可以和任意节点(包括自己)配对,需要特殊考虑。