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
",ans);
	return 0;
}
原文地址:https://www.cnblogs.com/Lour688/p/13229554.html