逆序对[模板]---离散化+树状数组(1月11日)

题目:

给出一个数组,求其逆序对个数,逆序对即ia[j]的对数!!

思路:

因为a[i]数比较大,且本题与a[i]本身大小无关,仅与元素直接差值有关,故先用离散化减少空间,然后将数组降序排序后表示每个元素出现的位置,然后用树状数组求和,有效且大大降低了时间复杂度!排序后a[i]数组是降序的,c[i]表示对应每个元素原本的位置,从前往后枚举一遍,每个数为后面比自己晚出现&&比自己小  (在后面了,说明肯定比它小)  贡献1;

例子:

原本a[i]:5 7 2 5 2 

a[i]:7 5 5 2 2

c[i]:2 4 1 5 3

代码如下:

#include
using namespace std;
using ll = long long;
ll n;
ll a[500005],c[500005],cnt[500005];
void add(ll x,ll k)
{
	for(ll i=x;i<=n;i+=i&-i)
	{
		cnt[i]+=k;
	}
}
ll query(ll x)
{
	ll sum=0;
	for(ll i=x;i;i-=i&-i)
	{
		sum+=cnt[i];
	}
	return sum;
}
ll cmp(ll x,ll y)
{
	if(a[x]==a[y]) return x>y;
	else return a[x]>a[y];//相同数字后出现在前面
}
void solve()
{ 
	cin>>n;
	ll ans=0;
	for(ll i=1;i<=n;i++)
	{
		cin>>a[i];
		c[i]=i;
	}
	sort(c+1,c+1+n,cmp);
	//5 7 2 5 2
	//变为
	//2 4 1 5 3
	//2为4,5,3贡献1,4为5贡献1,1为5,3贡献1,5不贡献,3不贡献
	//和为6
	for(ll i=1;i<=n;i++)
	{
		add(c[i],1);
		ans+=query(c[i]-1);
		//add(c[i],1);顺序都可以
	}
	/*树状数组作用:
	 用来求和运算,避免TLE
	 */
	
	cout<> t ;
	//for(ll i = 1 ; i <= t ; i++){
		// cout << "Case #" << i << ": "; 
		solve();
		//cout<<'\n';
	//}
}

你可能感兴趣的:(树状数组,离散化,c++,数据结构,算法)