还没写程序 但写一下我的思路把吧 以后好给自己明白。。。
1、主要是先建立第一个线段树,计算出他的逆序数,然后其它的用公式计算就行了。。
2、第一个树的建立。你存入一个点时,先查找出这个点与前边的点的逆序数,然后再把这个点写入你的树中。
(树中的每个节点除了叶子节点外,存的是我这个点所含盖的叶子节点中、实际存在的数的个数。所以啊 你写入叶子节点时,不要遍历的写,要把大的就写在大的上 比如 叶子节点a[i]存的就是i的这个数的情况,a[i].left=a[i].right=val 把他存进来,返回1。a[i].num=1;即我这个点的子树们有一个数了。)那你查找的时候从i+1 到n 查比他大的区域的a[].num就行了。即 比i大的值有num个
这几天学图论学乏了。。换个学学~所以就把之前没写的这个写了。
#include<stdio.h>
#include<string.h>
int n,w,s[50010];
int point[50010];
int find(int l,int r,int left,int right,int numb){
if(l==left&&r==right||numb>=w){
return s[numb];
}
int mid=(right+left)/2;
if(l>mid){
return find(l,r,mid+1,right,numb*2+1);
}
if(r<mid){
return find(l,r,left,mid-1,numb*2);
}
else{
return find(l,mid,left,mid,numb*2)+find(mid+1,r,mid+1,right,numb*2+1);
}
}
void updata(int root){
if(root==1){
s[root]++;
return;
}
s[root]++;
updata(root/2);
}
int main(){
while(scanf("%d",&n)!=EOF){
w=1;
while(w<n){
w*=2;
}
int sum=0,arr[5010];
memset(s,0,sizeof(s));
memset(point,0,sizeof(point));
for(int i=1;i<=n;i++){
scanf("%d",&arr[i]);
sum+=find(++arr[i],n,1,w,1);
updata(arr[i]+w-1);
}
int max=sum;
point[0]=sum;
for(int i=1;i<n;i++){
point[i]=point[i-1]+n-2*arr[i]+1;
if(point[i]<max){
max=point[i];
}
}
printf("%d\n",max);
}
return 0;
}