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

题目:

给出一个数组,求其逆序对个数,逆序对即i<j&&a[i]>a[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<bits/stdc++.h>
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<<ans<<'\n';
}
//-----------------------------------------------------------------------------------------
int main()
{
	//ll t = 1 ;
	//cin >> t ;
	//for(ll i = 1 ; i <= t ; i++){
		// cout << "Case #" << i << ": "; 
		solve();
		//cout<<'\n';
	//}
}

  • 17
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值