欢迎来到清街老酒的博客

どんな別れがあったとしても、出会ったことには必ず意味がある

求逆序对

求逆序对的常用方法(树状数组,归并排序,线段树)

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.归并排序

如归并过程中右边小于左边,则逆序对个数加mid-i+1;

#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.线段树

与树状数组原理类似,进行单点修改,查询区间和;

posted @ 2020-08-17 14:57  清街老酒  阅读(77)  评论(0编辑  收藏  举报