题目大意:给你一堆数,要只能在相邻交换成从小到大的序列。
思路:首先按照输入的数的下标用index记录
9 1 0 5 4
incex: 1 2 3 4 5
现在移动的方法可以这样,先找出最小的数,然后把它移到最前面,如0往前移动了2位,然后呢这时候我们就不必理会0了,以为已经是在自己的位置且在最前面,不影响后面的数;接下来呢就把1往前移动1位。如此类推呢,4移动2位,5移动了1位,所以最后答案是2+1+2+1=6次。
所以我们可以建一个线段树,把数组的下标放进去,并且每个结点都赋初值为1,如找0,那么0的index是3,则在[1,3)间记录有多少个数在0的前面,然后记录就把0这个结点值更新为0,即看作把0的这个结点删除了。所以建完树以后就按照大小排序好后逐个遍历且更新即可。
/* ***********************************************
┆ ┏┓ ┏┓ ┆
┆┏┛┻━━━┛┻┓ ┆
┆┃ ┃ ┆
┆┃ ━ ┃ ┆
┆┃ ┳┛ ┗┳ ┃ ┆
┆┃ ┃ ┆
┆┃ ┻ ┃ ┆
┆┗━┓ 马 ┏━┛ ┆
┆ ┃ 勒 ┃ ┆
┆ ┃ 戈 ┗━━━┓ ┆
┆ ┃ 壁 ┣┓┆
┆ ┃ 的草泥马 ┏┛┆
┆ ┗┓┓┏━┳┓┏┛ ┆
┆ ┃┫┫ ┃┫┫ ┆
┆ ┗┻┛ ┗┻┛ ┆
************************************************ */
#include <stdio.h>
#include <string.h>
#include <iostream>
#include <algorithm>
#include <vector>
#include <queue>
#include <stack>
#include <set>
#include <map>
#include <string>
#include <math.h>
#include <stdlib.h>
using namespace std;
#define inf 0x3f3f3f3f
#define ll long long
#define ull unsigned long long
#define lson rt<<1, l, mid
#define rson (rt<<1)|1,mid+1,r
#define maxn 500002
int cnt[maxn*3],index[maxn],num[maxn];
bool cmp(int i,int j)
{
return num[i]<num[j];
}
void update(int rt,int l,int r,int k,int value)
{
cnt[rt]+=value;
if(l==r)return ;
int mid=(l+r)>>1;
if(k<=mid)update(lson,k,value);
else update(rson,k,value);
}
int querry(int rt,int l,int r,int left,int right)
{
if(l>=left && r<=right)
return cnt[rt];
int mid=(l+r)>>1;
int ans=0;
if(left<=mid)ans+=querry(lson,left,right);
if(right>mid)ans+=querry(rson,left,right);
return ans;
}
int main()
{
//freopen("in.txt","r",stdin);
//freopen("out.txt","w",stdout);
int n;
while(~scanf("%d",&n),n)
{
ll ans=0;
memset(cnt,0,sizeof cnt);
memset(index,0,sizeof index);
memset(num,0,sizeof num);
for(int i=1;i<=n;i++)
{
scanf("%d",&num[i]);
update(1,1,n,i,1);
index[i]=i;
}
sort(index+1,index+1+n,cmp);
for(int i=1;i<=n;i++)
{
ans+=(querry(1,1,n,1,index[i])-1); //这里注意的是会把本身的1都加进去,所以要减去
update(1,1,n,index[i],-1);
}
printf("%I64d\n",ans);
}
return 0;
}