求逆序对的两种方法

1.利用归并排序求逆序对

注意:此种方法利用了归并排序每次归并后的有序性,需要归并的两组数据(p1遍历区间[start,mid]、p2遍历区间[mid + 1, end])在先前的归并中已经变得有序,因此这两组数据在归并时,只需要看右边nums[p2]是否小左边nums[p1],若小于,由于两组的数据已经变得有序(若大于,则继续做归并)因而存在区间[p1, m]中的所有数(即m - p1 + 1个数)与nums[p2]互为逆序对,将这两组数据合并后,(统计逆序数的在区间[mid + 1, end]中)nums[p2]会被归并到与之成逆序对的区间中,即消除这个数统计重复的逆序对的可能

#include<iostream>

using namespace std;

const int N = 100010;

int n;
long long cnt;
int nums[N];

void merge(int s, int m, int e){
    
    int tmp[N];
    int p0 = 0, p1 = s, p2 = m + 1;
    
    while(p1 <= m && p2 <= e)
/***************************关键代码***********************************/    
        if(nums[p1] <= nums[p2]) tmp[p0++] = nums[p1++];
        else{
            tmp[p0++] = nums[p2++];
            cnt += m - p1 + 1;
        }
/***************************关键代码***********************************/    
    while(p1 <= m) tmp[p0++] = nums[p1++];
    while(p2 <= e) tmp[p0++] = nums[p2++];
    
    for(int i = 0; i < e - s + 1; i++) nums[s + i] = tmp[i];
    
}


void merge_sort(int s, int e){
    int m = s + (e - s) / 2;
    
    if(s < e){
        merge_sort(s, m);
        merge_sort(m + 1, e);
        merge(s, m, e);
    }
    
}

int main()
{
    int n; 
    cin >> n;
    for(int i = 0; i < n; i++) cin >> nums[i];
    
    merge_sort(0, n - 1);
    
    //for(int i = 0; i < n; i++) cout << nums[i] << " ";
    cout << cnt;
    
    return 0;
}

2.用树状数组求逆序对

由于数组中的每个数是按顺序放入树状数组中的,因此找逆序对也就是找在i之前出现的所有数中比第i个数大的所有数的个数(即query(N) - query(i)), 树状数组维护的是原数组中、第i个数之前的所有数(类似于用了一个hash表来做查找)

#include<iostream>

using namespace std;

const int N = 1e6 + 10;  //依数组中值的范围而定

int tr[N], nums[N];

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

//add()从下向上加 
void add(int x, int v){
	
	for(int i = x; i <= N; i += lowbit(i)) tr[i] += v;
	
}

//query()从上向下查找 
int query(int x){
	
	int sum = 0;
	for(int i = x; i > 0; i -= lowbit(i)) sum += tr[i];
	return sum;
	
}

int main()
{
	int n;
	cin >> n;
	for(int i = 0; i < n; i++) cin >> nums[i];
	long long cnt = 0;
	
	//找出在nums[i]前被加入树状数组且比nums[i]大的数 
	
	for(int i = 0; i < n; i++){
		cnt += query(N) - query(nums[i]);
		add(nums[i], 1);
	}
	
	cout << cnt;
	return 0;
}
posted @ 2022-03-29 20:32  CDUT的一只小菜鸡  阅读(239)  评论(0编辑  收藏  举报