和小朋友排隊時一樣的題,線段樹+離散化+逆序數,注意求的是交換幾次,最後結果除2.
<span style="font-size:18px;">#include<iostream>
#include<stdio.h>
#include<math.h>
#include<string.h>
#include<vector>
#include<list>
#include<algorithm>
using namespace std;
#define MAX 500010
#define lson l,m,level*2
#define rson m+1,r,level*2+1
long long a[MAX];
long long b[MAX];
long long insert(long long l,long long r,long long level,long long x);
long long found(long long x);
struct node{
long long x;
long long l;
long long h;
}num[MAX];
long long n;
long long tree[MAX*5];
int main(){
scanf("%I64d",&n);
while(n){
for(long long i=1;i<=n;i++){
scanf("%I64d",&a[i]);
b[i] = a[i];
num[i].h = 0;
}
//離散化
sort(b+1,b+1+n);
for(long long i=1;i<=n;i++){
long long t = found(a[i]);
a[i] = t;
num[t].x = i;
b[t]--;
}
//線段樹插入
memset(tree,0,sizeof(tree));
long long sum = 0;
for(long long i=1;i<=n;i++){
num[a[i]].h = insert(1,n,1,a[i]); //點插入(按照原順序,計算比該點大的數的數目)
num[a[i]].l = a[i] - (num[a[i]].x - num[a[i]].h);
sum += num[a[i]].h + num[a[i]].l;
}
printf("%I64d\n",sum/2);
scanf("%I64d",&n);
}
return 0;
}
long long insert(long long l,long long r,long long level,long long x){
if(l==r&&l==x){
tree[level] = 1;
return 0; //注意該點不計入
}
long long m = (l+r)>>1;
long long temp;
if(x<=m){
temp = insert(lson,x);
temp += tree[level*2+1]; //加上比他大的數
}
else if(x>m){
temp = insert(rson,x);
}
tree[level] = tree[level*2] + tree[level*2+1]; //更新tree
return temp;
}
//二分
long long found(long long x){
long long l = 1,r = n;
long long mid;
while(l<r){
mid = (l+r)/2;
if(b[mid]==x){
if(b[mid-1]!=x) return mid;
else r = mid-1;
}
else if(b[mid]>x){
r = mid-1;
}
else if(b[mid]<x){
l = mid+1;
}
}
return l;
}</span>