歸併排序 求 逆序對

題目鏈接 洛谷P1908

引用該題題解中的一段話:

//在某個時候,左區間:  5 6 7  下標爲i
//           右區間:  1 2 9  下標爲j
//          
//這個時候我們進行合併:
//step 1:由於 5>1,所以產生了逆序對,這裏,我們發現,左區間所有還沒有被合併的數都比 1 大,所以1與左區間所有元素共產生了 3 個逆序對(即tot_numleft-i+1對),統計答案併合並 1 
//step 2:由於 5>2,由上產生了3對逆序對,統計答案併合並 2
//step 3:由於 5<9, 沒有逆序對產生,右區間下標 j++
//step 4:由於 6<9, 沒有逆序對產生,右區間下標 j++
//step 5:由於 7<9, 沒有逆序對產生,右區間下標 j++
//step 6:由於右區間已經結束,正常執行合併左區間剩餘,結束

//PS: tot_numleft=3,即左區間總元素個數

 

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 501000;

ll n,a[maxn],b[maxn];

ll cc(ll l,ll r)
{
	if(l>=r)
		return 0;
	ll mid = (l + r) / 2;
	ll ans = 0;
	ans+=cc(l, mid);
	ans+=cc(mid + 1, r);
	ll i, u, v;
	for (i = l, u = l, v = mid + 1; i <= r && u <= mid && v <= r; i++)
	{
		if(a[u]<=a[v])
		{
			b[i] = a[u];
			u++;
		}
		else
		{
			ans += mid - u + 1;
			b[i] = a[v];
			v++;
		}
	}
	if(u<=mid)
	{
		for (ll j = i; j <= r;j++)
		{
			b[j] = a[u++];
		}
	}
	if(v<=r)
	{
		for (ll j = i; j <= r;j++)
			b[j] = a[v++];
	}
	for (ll k = l; k <= r; k++)
		 a[k]=b[k];

	return ans;
}

int main()
{
	scanf("%lld", &n);
	for (ll i = 1; i <= n; i++)
		scanf("%lld", &a[i]);
	printf("%lld\n", cc(1, n));
	return 0;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章