Mấu chốt của bài này là với mỗi đỉnh u, ta cần tìm xem trong cây con có gốc
u có bao nhiêu đỉnh có giá trị nhỏ hơn u.
Để làm được điều trên, ta làm phẳng cây kết hợp với BIT. Cụ thể như sau:
Làm phẳng cây
Duyệt DFS trên cây, khi đi vào đỉnh, ta thêm đỉnh đó vào cuối mảng và sau khi đã
DFS xong tất cả các con của nó, ta cũng thêm đỉnh đó vào cuối mảng. Như vậy ta thấy,
trên mảng được tạo thành tất cả các con của đỉnh \(u\) đều nằm giữa 2 vị trí mà \(u\)
xuất hiện.
Ví dụ, cây trong đề bài là:
Mảng khi làm phẳng cây là:
Khi cài đặt ,ta lưu chỉ 2 số mà đỉnh xuất hiện trên mảng:
int count = 0;
int L[100000], R[100000];
void dfs(int u) {
L[u] = ++count;
for (int v: con[u]) dfs[v];
R[u] = ++count;
}
L lưu vị trí đầu tiên đỉnh xuất hiện và R lưu vị trí cuối cùng.
Sử dụng BIT để truy vấn
Sau khi đã làm phẳng cây, như đã nói ở trên thì với mỗi đỉnh \(u\), ta có một đoạn liên tiếp
từ \(L[u]\) đến \(R[u]\) chỉ gồm các đỉnh nằm trong cây con gốc \(u\). Đến đây bài toán trở nên đơn giản.
Ban đầu có một mảng \(A\) gồm \(2N\) phần tử \(0\), ta duyệt các đỉnh theo tiền lương tăng dần, ở mỗi bước
ta tăng \(A[L[v]]\) với \(v\) là đỉnh có tiền lương nhỏ hơn đỉnh đang xét. Sau đó truy vấn tính tổng từ
\(A[L[u]]\) đến \(A[R[u]]\) để tìm số đỉnh trong cây con gốc \(u\) có lương nhỏ hơn \(u\), tăng kết quả lên
một lượng \(c\times(c-1) / 2\).