关于树状数组,相信大家都已经比较熟悉了。。。
那么,我们就先来砍一刀例题(嘻嘻)
输入
给出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
",ans);
return 0;
}