【题目】
题目描述:
Prince 对他在这片大陆上维护的秩序感到满意,于是决定启程离开艾泽拉斯。在他动身之前,Prince 决定赋予 King_Bette 最强大的能量以守护世界、保卫这里的平衡与和谐。在那个时代,平衡是个梦想。因为有很多奇异的物种拥有各种不稳定的能量,平衡瞬间即被打破。KB 决定求助于你,帮助他完成这个梦想。
一串数列即表示一个世界的状态。
平衡是指这串数列以升序排列,而从一串无序数列到有序数列需要通过交换数列中的元素来实现。KB 的能量只能交换相邻两个数字。他想知道他最少需要交换几次就能使数列有序。
输入格式:
第一行为数列中数的个数
n
n
n(
n
n
n ≤
100000
100000
100000)。
第二行为
n
n
n 个数
a
1
a_1
a1~
a
n
a_n
an (每个数小于
100000
100000
100000),表示当前数列的状态。
输出格式:
输出一个整数,表示最少需要交换几次能达到平衡状态。
样例数据:
输入
4
2 1 4 3
输出
2
备注:
本题另外一种描述:
给定一个序列
a
1
a_1
a1,
a
2
a_2
a2,…,
a
n
a_n
an,如果存在
i
<
j
i<j
i<j 并且
a
i
>
a
j
a_i>a_j
ai>aj ,那么我们称之为逆序对,求逆序对的数目。
【分析】
一道逆序对模板题,之前写过如何用归并排序求逆序对(不知道怎么写的可以戳这里),现在写一下如何用树状数组求
大概的思路就是每加入一个数,就去找之前比它大的数的个数,具体操作如下:
- add(x,1):每加入一个数,就把这个数的数量增加 1
- sum(x):查询 1~x 之间数的个数,也就相当于是小于等于 x 的数,那么 i-sum(x) 就应该是大于 x 的数了
时间复杂度为 O( n ∗ l o g    n n*log\;n n∗logn),和归并一样,不过用树状数组的话要好写一点,还是推荐用树状数组写
P s Ps Ps:这道题数据比较温柔,如果 a i a_i ai 更大一点(如 1 0 9 10^9 109),就要用到离散化了
【代码】
#include<cstdio>
#include<cstring>
#include<algorithm>
#define N 100005
#define lowbit(x) x&-x
using namespace std;
int tree[N];
void add(int i,int x)
{
while(i<N)
{
tree[i]+=x;
i+=lowbit(i);
}
}
int sum(int i)
{
int ans=0;
while(i>=1)
{
ans+=tree[i];
i-=lowbit(i);
}
return ans;
}
int main()
{
int n,i,x;
long long ans=0;
scanf("%d",&n);
for(i=1;i<=n;++i)
{
scanf("%d",&x);
add(x,1);
ans+=i-sum(x);
}
printf("%lld",ans);
return 0;
}