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.
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.
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.
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With