DuyMinh3005's blog

By DuyMinh3005, 3 days ago, In English

This blog's target audience is for newbies who don't know this (like me!). So, if you knew this before, it would be great if you read this blog and give me some valuable feedbacks. Thanks ^^!

Now for the intro:

A while ago, I met a problem where it requires me to count the number of inversion of an array. Having 2 braincells, I knew nothing about this. So, I decided to ask my friends ballss and quanhoangbla. Of course, they are good friends so they taught me everything about that. NO. ballss just called me dumb, so I decided to learn it myself. That's when I stumbled across this blog. This blog, in my opinion, is a great blog, but it was not really well written. As a result, it got heavily downvoted (I recommend you upvote that blog, although it's most likely that the author have stopped doing CP, since the last time he/she visited was 9 months ago). Although I understand the main idea, I think that it might be confusing for other newbies too. So, I decided to rewrite that blog, to understand about this topic more and to contribute to the community :D.

Also, as you can notice from the title, this is the first part of this series. If I'm not lazy, I may write some more parts. If you want me to rewrite a blog, you can DM me for that topic.

NOTE THAT ALL OF THE IDEAS IN THIS BLOG WERE FROM THIS BLOG. WHAT I DO IS JUST REWRITE THAT BLOG SO THAT IT'S EASIER TO UNDERSTAND

Now, for the main part of the blog:


Counting inversion using mergesort/fenwick tree


Problem statement:

You were given an array $$$a$$$ of size $$$n$$$ $$$(1 ≤ n ≤ 10^5,$$$ $$$a_i ≤ 10^5$$$ $$$\forall$$$ $$$1 ≤ i ≤ n)$$$. Count the number of inversion in this array.

What's an inversion count?

Naive approach: Brute force


Since the constraint of $$$n$$$ is up to $$$10^5$$$, so this approach will certainly get TLE. Tho, I think it's good to have this part so that you can understand the correct solution better.

The main idea of this method is to use 2 for loops to iterate through all of the possible pair of index. Then, you check if they sastify the condition. If yes, increase the count by 1.

Code:

Time complexity: $$$O(n^2)$$$
Space complexity: $$$O(n)$$$


Solution 1: Using Mergesort

It is recommended to read this blog to know more about merge sort

If you are lazy reading the blog above, what is merge sort?

For the main idea of this method:

You need to count the number of inversions in the array $$$a$$$. You split them into 2 halves: array $$$b$$$ and $$$c$$$ (array $$$b$$$ contains the first half of array $$$a$$$, and array $$$c$$$ contains the second half). Assume that you have the inversion count for array $$$b$$$ and $$$c$$$. So, to get the inversion count of array $$$a$$$, you need to add the number of inversions in array $$$b$$$, array $$$c$$$, and the cross inversions (the number of index $$$i$$$ and $$$j$$$ so that, $$$i$$$ is in array $$$b$$$, $$$j$$$ is in array $$$c$$$ and $$$a_i \gt a_j$$$. This is an inversion since $$$i \lt j$$$). Think how to count this.

Hint:
Solution:
Code: (Maybe it's going to be a little bit hard to understand, I tried my best to make it easy to comprehend, sorry for any inconvenience)

Time complexity: $$$O(n$$$ $$$log$$$ $$$n)$$$
Space complexity: $$$O(n)$$$


Solution 2: Using Fenwick tree

It is recommended to read this blog to understand what is Fenwick tree. Explaining this is quite long so, for the sake of simplicity, assume that you know how fenwick tree works (by reading the blog I recommended) ^^

The main idea of this algorithm is, you build a frequency array, let's call it $$$freq$$$. Then, $$$freq_i$$$ will be the number of times that $$$i$$$ appeared. So, the number of indexes that are less than are equal to $$$i$$$ would be

$$$freq_1 + freq_2 + ... + freq_i = prefix_i$$$

Where $$$prefix_i$$$ is the prefix sum of the first $$$i$$$ elements in array $$$freq$$$. You can get this value in $$$log$$$ $$$n$$$ time using fenwick tree.

So, to count the number of inversions in an array $$$a$$$, initially, we set the array $$$freq$$$ to $$$0$$$. Then, you would need to iterate $$$x$$$ in array $$$a$$$ from back to front. After that, you add the numbers of indexes that are less than $$$a_x$$$ to the answer, which is the $$$prefix_{a_x - 1}$$$ to the array. This can be done in $$$log$$$ $$$n$$$ time. Note that you add $$$prefix_{a_x - 1}$$$, not $$$prefix_{a_x}$$$ since you need to count the number of elements that are less than $$$a_x$$$, not less than or equal to $$$a_x$$$.

Finally, you update the $$$freq_{a_x}$$$ by one. This mean that, you need to update the $$$prefix$$$ array as well. This can also be done in $$$log$$$ $$$n$$$ time using fenwick tree.

Code:

Time complexity: $$$O(n$$$ $$$log$$$ $$$n)$$$
Space complexity: $$$O(n)$$$

Bonus (this isn't in the original blog):

As you can see, the fenwick tree can only store elements that are less than are equal to $$$10^7$$$ (since that's the memory limit for an array in C++, I don't know for other languages). So, if the problem gives you $$$a_i$$$ up to $$$10^{18}$$$, what would you do? Of course, you can still use merge sort, but fenwick tree is way easier to implement.

Solution + code:

So, that's the end of the blog! This is my first time posting something useful (as the others are mostly shitposts -_-), so I hope that you like this. Also, if you want me to rewrite any blog, message me. (Of course, please send me a blog that I can understand, not a FFT blog...).

Thank you for reading, and have a nice day ;)

  • Vote: I like it
  • +1
  • Vote: I do not like it