P1908 逆序对

求逆序对

  • 逆序对是什么呢?就是说在一个序列中,如果i<j但是\(a_i>a_j\)那么(\(a[i],a[j]\))就是一个逆序对,是无序的。
  • 通俗的说,逆序对就是就是一个数与在它后面且比他小的数组成的数对。
  • 树状数组可以用来求逆序对,是利用它能求前缀/后缀和的原理
  • 将一个1~N的数组由后向前遍历,每次遍历到\(a_i\)时,在树状数组下标为\(a_i\)的地方+1,并向后一直到N维护前缀和,遍历到\(a[i]\)时,求Q(\(a[i]-1\))即\(a[i]\)与其后面的数组成的逆序对个数
    (注意一下离散化方法,因为洛谷上用map会超时)

Code

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
const int maxn=5e5+5;
int t[maxn],a[maxn],n,tot;
long long ans;
inline long long rd(){
	register int x=0,f=0;register char ch=getchar();
	while(ch<'0'||ch>'9')f|=ch=='-',ch=getchar();
	while(ch>='0'&&ch<='9')x=(x<<3)+(x<<1)+(ch^48),ch=getchar();
	return f?-x:x;
}
void A(int x,int a){
	for(;x<=n;x+=x&-x)t[x]+=a;
}
int Q(int x){
	int ans=0;
	for(;x;x-=x&-x)ans+=t[x];
	return ans;
}
struct Node{
	int id,data;
}node[maxn];
bool cmp(Node a,Node b){
	return a.data<b.data;  
}
int main(){	
//	freopen("1.in","r",stdin);
	scanf("%d",&n);
	for(int i=1;i<=n;++i){
		node[i].data=rd();
		node[i].id=i;
	}
	sort(node+1,node+1+n,cmp);//离散化
	for(int i=1;i<=n;++i){
		if(node[i].data>node[i-1].data){//赋予其小点的数,我们只需要知道其相对位置即可
			a[node[i].id]=i;
		}else a[node[i].id]=a[node[i-1].id];//处理相等情况,离散化为一个数值
	}
	for(int i=n;i>=1;--i){
		ans+=(long long)Q(a[i]-1);
		A(a[i],1);
	}
	printf("%lld\n",ans);
	return 0;
}
posted @ 2020-07-03 15:20  liuzhaoxu  阅读(101)  评论(0编辑  收藏  举报