大概是NOIP前最后一场模拟赛了,yj组织的信心赛。
题目大意:
- 给出一棵 n n n 个节点的树,以及一个空序列。
- 每个节点上有一个取值在 { 0 , 1 } \{0, 1\} {0,1} 中的数。
- 每次你可以选择没有父亲节点的点删除,并且将这个节点上的数字放在当前数列末尾。
- 请你求出这个数列可能得到的最小逆序对数。
- n ≤ 2 × 1 0 5 n \leq 2 \times 10^5 n≤2×105。
难点在于贪心策略基于整棵树,而不能只通过独立点的子树合并。
很久没做过类似的贪心了,思想很经典,用Exchange Argument
的方法来构造正确的贪心策略。在我的理解层面上是先进行假设,通过假设某策略更优,接着得到该策略更优所需具备的条件,最终将贪心策略用权值大小来表示。
题解:题目要求逆序对数最小,首先想到尽量让最终得到接近00...01...11
的数列。发现当父节点进行扩展时,先选
v
a
l
val
val 为 0 的子节点一定不劣。所以可以先将
v
a
l
val
val 为 0 的节点与其父亲合并再进行贪心。
基于这一想法,可以考虑节点与父亲合并。由于父节点一定在子树前面入队,所以父与子的逆序对数恒定,那么只需考虑子树间合并的先后关系。
这时候就要用到Exchange Argument
的思想了,可以发现在原先合并的基础上,(合并后)每个节点都代表了若干
v
a
l
=
0
val=0
val=0 的点和若干
v
a
l
=
1
val=1
val=1 的点。考虑此时对于子树
i
,
j
i,j
i,j 合并的先后顺序,若先拓展
i
i
i 再拓展
j
j
j,则新增的逆序对数为
c
n
t
1
i
×
c
n
t
0
j
cnt_1i\times cnt_0j
cnt1i×cnt0j,其中
c
n
t
0
/
1
x
cnt_{0/1} x
cnt0/1x 表示节点
x
x
x 代表
c
n
t
0
/
1
cnt_{0/1}
cnt0/1 的 0/1。同理,若先拓展
i
i
i 再拓展
j
j
j,则新增的逆序对数为
c
n
t
1
j
×
c
n
t
0
i
cnt_1j\times cnt_0i
cnt1j×cnt0i。显然,假设先拓展
i
i
i 比先拓展
j
j
j,则应满足
c
n
t
1
i
×
c
n
t
0
j
<
c
n
t
1
j
×
c
n
t
0
i
cnt_1i\times cnt_0j<cnt_1j\times cnt_0i
cnt1i×cnt0j<cnt1j×cnt0i,即
c
n
t
1
i
c
n
t
0
i
<
c
n
t
1
j
c
n
t
0
j
\large\frac{cnt1_i}{cnt_0i}<\frac{cnt_1j}{cnt_0j}
cnt0icnt1i<cnt0jcnt1j。所以只需将每个点的
c
n
t
1
i
c
n
t
0
i
\large\frac{cnt_1i}{cnt_0i}
cnt0icnt1i 放进优先队列,依次合并即可。
注意到分母可能为0,此时其所代表的权值为
+
∞
+\infin
+∞,直接将其赋值为
+
∞
+\infin
+∞ 就行。
对答案的贡献可以在合并时完成。
这题最重要的点是Exchange Argument
构造贪心策略的方法,比如对于一道单纯靠子树合并难以完成的题目(像这题,拓展的过程长得像bfs的),可以尝试假设
a
a
a 比
b
b
b 优相应需要的条件,后将贪心策略转化为单纯的权值比较、合并,可以解决部分普通贪心不好解决的问题。