1. 程式人生 > 實用技巧 >求逆序對

求逆序對

求逆序對的常用方法(樹狀陣列,歸併排序,線段樹)

1.樹狀陣列

首先對陣列b[i]進行離散化處理,按價值從大到小排序得到位置陣列a[i],排序後用樹狀陣列維護,將a[i](數從大到小排序後的位置)依次加入樹狀陣列,然後依次查詢a[i]位置前面一位的數,答案相加即為逆序對個數。
例:洛谷P1908 逆序對

#pragma GCC optimize("Ofast")
#pragma GCC target("avx,avx2,fma")
#pragma GCC optimize ("unroll-loops")
#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<math.h>
#include<string>
#include<queue>
#include<map>
#include<stack>
#include<iostream>
#define INF 0x3f3f3f3f
#define lowbit(a) ((a)&-(a))
typedef long long ll;
typedef unsigned long long ull;
using namespace std;
int n,c[500005],a[500005],b[500005];
void update(int x,int y,int n)
{
	for(int i=x;i<=n;i+=lowbit(i))
	{
		c[i]=c[i]+y;
	}
}
ll getsum(int x)
{
	ll ans=0;
	for(int i=x;i;i-=lowbit(i))
	{
		ans+=c[i];
	}
	return ans;
}
int cmp(int s1,int s2)
{
	if(b[s1]==b[s2])
	return s1>s2;
	else
	return b[s1]>b[s2];
}
int main()
{
	ll ans=0;
	cin>>n;
	for(int i=1;i<=n;i++)
	{
		scanf("%d",&b[i]);
		a[i]=i;
	}
	sort(a+1,a+1+n,cmp);
	for(int i=1;i<=n;i++)
	{
		update(a[i],1,n);
		ans+=getsum(a[i]-1);
	}
	cout<<ans<<endl;
} 

2.歸併排序

如歸併過程中左邊大於右邊,則逆序對個數加一;

#pragma GCC optimize("Ofast")
#pragma GCC target("avx,avx2,fma")
#pragma GCC optimize ("unroll-loops")
#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<math.h>
#include<string>
#include<queue>
#include<map>
#include<stack>
#include<iostream>
#define INF 0x3f3f3f3f
#define lowbit(a) ((a)&-(a))
typedef long long ll;
typedef unsigned long long ull;
using namespace std;
int n,a[500010],c[500010];
long long ans;
void msort(int b,int e)//歸併排序
{
    if(b==e)  
		return;
    int mid=(b+e)/2,i=b,j=mid+1,k=b;
    msort(b,mid),msort(mid+1,e);
    while(i<=mid&&j<=e)
    	if(a[i]<=a[j])
    		c[k++]=a[i++];
    	else
    		c[k++]=a[j++],ans+=mid-i+1;//統計答案
    while(i<=mid)
    	c[k++]=a[i++];
    while(j<=e)
    	c[k++]=a[j++];
    for(int l=b;l<=e;l++)
    	a[l]=c[l];
} 

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

3.線段樹

與樹狀陣列原理類似,進行單點修改,查詢區間和;