Inverse pair --- tree array

topic description

Tom, the cat, and Jerry, the mouse, have recently competed again, but after all, they are both adults. They no longer like to play that kind of game of chasing each other. Now they like to play statistics.

Recently, TOM Lao Mao looked up something that humans call "reversed pair", which is defined as follows: For a given sequence of positive integers, a reversed pair is a_i>a_jai​>aj​ and i< An ordered pair of ji<j. After knowing this concept, they will compete who can first calculate the number of reversed pairs in a given sequence of positive integers. Note that there may be repeated numbers in the sequence.

answer

        The inverse pair had an O(nlogn) level solution at the beginning of learning merge sorting, which was already relatively fast. Then I learned about tree arrays today and found another O(nlogn) solution, but in This question may be a little slower, and I have borrowed some other people's solutions.

        Count how many reverse pairs there are in a sequence, that is, find how many numbers are greater than this number before each number. As long as each number comes in, I can directly query how many numbers are larger than this number, then the task can be completed, so a suffix and an array can be used to maintain the number of numbers larger than this number after each addition of this number Number, so as to achieve fast query, for example, if 3 is added, then 1 and 2 must be added by 1, because 1, 2, both have a number larger than this number, and then if 2 is added, 2 is already 1 at this time Yes, directly add 1 to the answer, but it is time-consuming to add to the interval each time. At this time, the difference array is introduced to update the points, that is, the addition operation of the tree array; at the same time, the sum of the suffixes can be obtained for each point value, which is actually the query operation of the tree array.

Two questions :

        1. The data range here is 1e9 , so it is actually unrealistic to maintain such a large range of data, no matter whether it is space or time, but what is special here is that there is only a relationship between numbers, 1 2 3 and 1 2 10 are essentially the same , so as long as the array is sorted, the number is used to reassign each number, and the size of the form can be used for statistics. For example, 1 10 100 is directly transformed into 1 2 3, so the maintenance length of 1e5 This is acceptable.

        2.  I still don’t know much about the suffix sum, so I converted it into a prefix sum, so that the difference sum is more familiar and intuitive. The difference is that it should be reversed. 10 100 turns into 3 2 1, and then counts how many numbers are smaller than it when each number is added. The reason is still the same. Why and how to turn are as follows.

           Let's talk about sorting in detail here. Each number can be read as a structure, which stores the number and size of each number, and then sort the array of structures, first sorting by size, if the size is the same, put the one that came in first in front.

        The specific process is as follows. It is necessary to count how many values ​​are smaller than this after entering a value each time . For example, 1 3 3 2, first sorted as 3(2) 3(3) 2(4) 1(1), inside the brackets is the number of occurrences, observe that the first one appears in the second one, we now hope to put the number The two numbers that appear are equivalently replaced with one number, which is the number, so f[2]=1, repeat the operation, and renumber it to 4 1 2 3. Set the initial value ans=0, the difference array b, the first one gets 4, and finds that b(4) is 0, that is, there is no one smaller than 4, ans is still 0, update b[5]+1, which means All +1 greater than 4, so assuming that a 5 comes, then the sum of the differences, sum(5)=b(1)+...b(5)=1, can be added to ans.

        Because this solution involves sorting, it is also O(nlogn), so it may be slower than merging, but if you don't need to sort, that is, the data range is small, it is not necessarily so.

Here is the code: 

#include<stdio.h>
#include<algorithm>
#define ll long long
using namespace std;
int n;
ll ans = 0;
int f[600000];
int t[600000];
struct node
{
	int num;//实际数据
	int bh;//编号
}a[600000];

int lowbit(int x)
{
	return x & (-x);
}

void add(int x, int k)
{
	while (x <= n)
	{
		t[x] += k;
		x = x + lowbit(x);
	}
}

int ask(int x)
{
	int ans = 0;
	while (x)
	{
		ans += t[x];
		x -= lowbit(x);
	}
	return ans;
}

int cmp(node x, node y)
{
	if (x.num != y.num)
	{
		return x.num > y.num;
	}
	else
	{
		return x.bh > y.bh;
	}
}
int main()
{
	scanf("%d", &n);
	for (int i = 1; i <= n; i++)
	{
		scanf("%d", &a[i].num);
		a[i].bh = i;
	}
	sort(a + 1, a + n + 1, cmp);//排序,大小相同,次序优先,保证相同的值不能算逆序对
	for (int i = 1; i <= n; i++)//重新编号操作
		f[a[i].bh] = i;
	for (int i = 1; i <= n; i++)//树状数组
	{
        //利用差分计算
		ans += ask(f[i]);
		add(f[i] + 1, 1);
	}
	printf("%lld", ans);
	return 0;
}

Guess you like

Origin blog.csdn.net/weixin_60360239/article/details/128425011