主题思想: 用线段树,或者树状数组求出给出序列的逆序数,
利用线段树求逆序数的思路是: 线段0-n-1 表示给出的序列。 依次读入序列的值 ai ,查询线段树i之后已经读入的值,因为是按顺序读入序列的,如果读入ai查询,i之后的线段的值,如果不为0,表示在i之前没有比ai大的数,否则,则证明,读入ai时,在i之前,已经有比ai大的数,这些数与ai构成逆序对。
然后再更新线段树i节点 为1 表示已经读入此值。
线段树节点保存,一个线段中有多少个数已经读入。
AC代码:
#include <iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
using namespace std;
const int maxn=5005;
int a[maxn*4];
int x[maxn];
void pushup(int i){
a[i]=a[i<<1]+a[i<<1|1];
}
void build(int l,int r,int i){
a[i]=0;
if(l==r){
return ;
}
int mid=l+(r-l)/2;
build(l,mid,i<<1);
build(mid+1,r,i<<1|1);
}
void update(int p,int l,int r,int i){
if(l==r){a[i]=1;return;}
int mid=l+(r-l)/2;
if(p<=mid) update(p,l,mid,i<<1);
else update(p,mid+1,r,i<<1|1);
pushup(i);
}
int query(int ql,int qr,int l,int r,int i){
if(ql<=l&&r<=qr){
return a[i];
}
int ans=0;
int mid=l+(r-l)/2;
if(qr<=mid) ans+=query(ql,qr,l,mid,i<<1);
else if(ql>mid) ans+=query(ql,qr,mid+1,r,i<<1|1);
else{
ans+=query(ql,qr,l,mid,i<<1);
ans+=query(ql,qr,mid+1,r,i<<1|1);
}
return ans;
}
int main()
{
int n;
int sum=0;
while(scanf("%d",&n)!=EOF){
memset(a,0,sizeof(a));
sum=0;
build(0,n-1,1);
for(int i=0;i<n;i++){
scanf("%d",&x[i]);
sum+=query(x[i],n-1,0,n-1,1);
update(x[i],0,n-1,1);
}
int tmp=sum;
for(int i=0;i<n;i++){
sum+=(n-2*x[i]-1);
tmp=min(tmp,sum);
}
printf("%d\n",tmp);
}
return 0;
}
树状数组实现:
首先树状数组从下标1 开始,所以a[i] 对应c[a[i]+1] 读入a[i]时,就把c[a[i]+1]更新为1 ,初始全为0,
另外树状数组,用两次查询,才能实现,线段树的区间查询功能
AC 代码:
#include <iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
using namespace std;
const int maxn=5005;
int a[maxn];
int c[maxn]; // binary indexed array
int n;
int lowbit(int x){
return x&(-x);
}
void init(){
for(int i=1;i<=n;i++){
if(i%2==1) c[i]=a[i];
else{
int k=lowbit(i);
for(int j=i-k+1;j<=i;j++){
c[i]+=a[j];
}
}
}
}
void change(int i,int x){
while(i<=n){
c[i]+=x;
i+=lowbit(i);
}
}
int query(int n){
int sum=0;
while(n!=0){
sum+=c[n];
n-=lowbit(n);
}
return sum;
}
int main()
{
int sum=0;
int tmp=0;
while(scanf("%d",&n)!=EOF){
sum=0;
tmp=0;
memset(c,0,sizeof(c));
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
//query
sum+=query(n)-query(a[i]+1);
//update
change(a[i]+1,1);
}
tmp=sum;
for(int i=1;i<n;i++){
sum+=(n-2*a[i]-1);
tmp=min(tmp,sum);
}
printf("%d\n",tmp);
}
return 0;
}