We mentioned BinaryIndexedTree and TreeList in previous post. Now I will give an example problem where both data structure are needed.

Given array a[0…n-1], which stores a permutation of 0 to n-1. We define array b[0…n-1] using following equation:

b[i]=|{x|x occurs before i in a[], and x > i}|

The problem is: given a[], compute b[] in O(nlogn) time; given b[], compute a[] in O(nlogn) time.

To convert a[] into b[], assume we have an array t[0…n](initially all 0). We go through each elements in a[], and for each element a[i] we encounter, b[a[i]]=t[0]+…+t[a[i]], and then we set t[a[i]]=1. The correctness is obvious. Implementing this method naively gives O(n^2). Notice that binary indexed tree is designed for this kind of prefix sum operation:

[sourcecode language=”cpp”]

vector<int> a2b(vector<int> a){

vector<int> b(a.size());

BITWraper t(a.size(),0);

for (int i = 0; i < a.size(); i++) {

b[a[i]]=i-t.sum(a[i]);

t.add(a[i]);

}

return b;

}

[/sourcecode]

By default, binary indexed tree’s array index starts from 1. Thus, we implemented a wrapper class, which allows arbitrary starting index.

How to computing a[] given b[]? Let’s look at large elements first. Let’s first write down the largest element, for each elements i, there are b[i] elements greater than it. Since we write down elements in descending order, all b[i] elements must have been written down. Thus, we insert i into b[i] position. After all elements are inserted, a[] is constructed. Again, implementing using array or linked list will result in O(n^2) complexity, while TreeList only need O(nlogn) time to do all insertions.

[sourcecode language=”cpp”]

vector<int> b2a(vector<int> b){

TreeList<int> a;

for(int i=b.size()-1;i>=0;i–)

a.insert(i,b[i]);

return a.toVector();

}

[/sourcecode]