Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to count number of inversions in an array using segment trees

I know that this problem can be solved using modified merge sort and I have coded same. Now I want to solve this problem using Segment Tree. Basically, if we traverse from right to left array then we have to count the "how many values are greater than current value". How this thing can be achieved by Segment Tree?

What type of information we have to store on Segment Tree Node?

Please provide code if possible.

like image 442
Namit Rawal Avatar asked Sep 12 '13 07:09

Namit Rawal


People also ask

How is inversion number calculated?

The inversion number of a permutation is the total number of inversions. One way to help calculate the inversion number is to look at each position in the permutation and count how many smaller numbers are to the right, and then add those numbers up.

How do you count bits using inversions?

We can count inversions by grouping them by second element. For example, in the array [4, 3, 1, 2], the element pairs (4, 3), (4, 1), (4, 2), (3, 1), and (3, 2) are inversions.

What does the number of inversions in an array indicate *?

The inversions of an array indicate; how many changes are required to convert the array into its sorted form. When an array is already sorted, it needs 0 inversions, and in another case, the number of inversions will be maximum, if the array is reversed.


1 Answers

Let me explain step by step with an example:

arr      :  4 3 7 1
position :  0 1 2 3

First, sort the array in descending order as {value, index} pair.

arr      :  7 4 3 1
index    :  2 0 1 3
position :  0 1 2 3

Iterating from left to right, for each element arr[i] -

Query for each element's index (query for range [0, arr[i].index] to get the greater numbers count on left side) and put the query result on corresponding index of output array.

After each query, increment the corresponding segment tree node which covers that index.

This way, we are ensuring to get only greater numbers count from 0 to index - 1 as values only greater than arr[i] have been inserted so far.

Below C++ implementation will make more sense.

class SegmentTree {

    vector<int> segmentNode;

public:
    void init(int n) {
        int N = /* 2 * pow(2, ceil(log((double) n / log(2.0)))) - 1 */ 4 * n;
        segmentNode.resize(N, 0);
    }

    void insert(int node, int left, int right, const int indx) {
        if(indx < left or indx > right) {
            return;
        }
        if(left == right and indx == left) {
            segmentNode[node]++;
            return;
        }
        int leftNode = node << 1;
        int rightNode = leftNode | 1;
        int mid = left + (right - left) / 2;

        insert(leftNode, left, mid, indx);
        insert(rightNode, mid + 1, right, indx);

        segmentNode[node] = segmentNode[leftNode] + segmentNode[rightNode];
    }

    int query(int node, int left, int right, const int L, const int R) {
        if(left > R or right < L) {
            return 0;
        }
        if(left >= L and right <= R) {
            return segmentNode[node];
        }

        int leftNode = node << 1;
        int rightNode = leftNode | 1;
        int mid = left + (right - left) / 2;

        return query(leftNode, left, mid, L, R) + query(rightNode, mid + 1, right, L, R);
    }

};

vector<int> countGreater(vector<int>& nums) {
    vector<int> result;
    if(nums.empty()) {
        return result;
    }
    int n = (int)nums.size();
    vector<pair<int, int> > data(n);
    for(int i = 0; i < n; ++i) {
        data[i] = pair<int, int>(nums[i], i);
    }
    sort(data.begin(), data.end(), greater<pair<int, int> >());
    result.resize(n);
    SegmentTree segmentTree;
    segmentTree.init(n);
    for(int i = 0; i < n; ++i) {
        result[data[i].second] = segmentTree.query(1, 0, n - 1, 0, data[i].second);
        segmentTree.insert(1, 0, n - 1, data[i].second);
    }
    return result;
}

// Input : 4 3 7 1
// output: 0 1 0 3

This is easy one but not pretty "obvious" as other typical segment tree problem. Simulating with pen and paper with an arbitrary input will help.

There are other O(nlogn) approaches with BST, Fenwick tree and merge sort.

like image 194
Kaidul Avatar answered Nov 15 '22 04:11

Kaidul