题目链接:https://www.jisuanke.com/course/615/28134
题目大意:给你一个序列,将它排列成升序,最少的交换次数是多少?
题目思路:
一次有效的交换意味着什么呢?为了使序列有序,一次有效的交换应该是后一个较小的数与他前一个较大的数交换,那么单独一个数字的交换次数,应该是这个数字前面比它大的数字的个数。
所以我们就可以根据树状数组统计出小于等于它的数的和,从而统计出比它大的数的个数。
注意的点:由于数据过大数组不能开的太大,所以先要将数据离散化,然后在采用树状数组的方式解决问题。
代码:
#include <bits/stdc++.h>
using namespace std;
#define ll long long
const int n=500020;
int tree[n];
//更新树状数组
int number[n];
int num_f[n];
void add(int k,int num)//k是坐标位置,num是变化大小
{
while(k<=n) //n是数组的大小
{
tree[k]+=num;
k+=k&-k;//lowbit(k),比如10100得出来的就是100 11101000得出来的就是1000
}
}
int update(int x,int y,int num)
{
add(x,num);
add(y+1,-num);
}
//求和 1~k
int read(int k)
{
int sum=0;
while(k){
sum+=tree[k];
k-=k&-k;
}
return sum;
}
int main()
{
ll ans=0;
int m;scanf("%d",&m);
for(int i=0;i<m;i++){
scanf("%d",&number[i]);
num_f[i]=number[i];
}
//离散化
sort(num_f,num_f+m);
int size=unique(num_f,num_f+m)-num_f;
for(int i=0;i<m;i++)
number[i]=lower_bound(num_f,num_f+size,number[i])-num_f+1;
for(int i=0;i<m;i++){
add(number[i],1);
ans+=i+1-read(number[i]);
}
printf("%lld\n",ans);
}