咳咳,用树状数组求逆序对及例题

关于树状数组,相信大家都已经比较熟悉了。。。
那么,我们就先来砍一刀例题(嘻嘻)

输入

给出n以及n个数,求这其中的逆序对个数
PS:逆序对,就是序列中ai>aj且i<j的有序对。
输入:
6
5 4 2 6 3 1
输出:
11
n<=5*10^5
ai<=10^9

嗯。。。
这一题,很多人应该都会选择归并求逆序对吧。。。
但是,树状数组求逆序对我们也应该要掌握掌握的说。
那么,想让我们想一想,逆序对应该怎么快速求呢?
我们可以倒着枚举。

void add(int x) {for (;x<=n;x+=lowbit(x)) t[x]++;}

int total(int x) {int s=0; for (;x>0;x-=lowbit(x)) s+=t[x]; return s;}

for (int i=n;i>0;i--)
	add(c[i]),ans+=total(c[i]-1);

因为ai<=10^9,我们很容易就能想到离散化
这个离散化呢,还要小心一点就是相等的情况。

n=read();//read()为读入优化
for (int i=1;i<=n;i++) a[i]=(node){read(),i};
sort(a+1,a+n+1,cmp);c[a[1].num]=1;
for (int i=2;i<=n;i++)
{
	if (a[i].val!=a[i-1].val) tot++;
	c[a[i].num]=tot;
}

这样,我们就能简单而又容易地打出代码啦!

#include<cstdio>
#include<algorithm>
#define ll long long
#define lowbit(x) x&-x
#define N 500010
using namespace std;
struct node{ll val,num;}a[N];
ll ans=0,t[N]={0},c[N];int n,tot=1;

inline int read()
{
    int x=0,f=1; char c=getchar();
    while(c<'0' || c>'9') f=(c=='-') ? -1:f,c=getchar();
    while(c>='0' && c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
    return x*f;
}

int cmp(node x,node y) {return x.val<y.val;}

void add(int x) {for (;x<=n;x+=lowbit(x)) t[x]++;}

ll total(int x) {ll s=0; for (;x>0;x-=lowbit(x)) s+=t[x]; return s;}

int main()
{
//	freopen("nxd.in","r",stdin);
//	freopen("nxd.out","w",stdout);
	n=read();
	for (int i=1;i<=n;i++) a[i]=(node){read(),i};
	sort(a+1,a+n+1,cmp);c[a[1].num]=1;
	for (int i=2;i<=n;i++)
	{
		if (a[i].val!=a[i-1].val) tot++;
		c[a[i].num]=tot;
	}
	for (int i=n;i>0;i--)
		add(c[i]),ans+=total(c[i]-1);
	printf("%lld\n",ans);
	return 0;
}

猜你喜欢

转载自blog.csdn.net/Larry1118/article/details/84677774