参考题解之后,AC!
算是NOIP2011后的线段树第一题!
逆序对数——经典问题吧。
逆序对数有一个性质,见DISCUSS。
统计某一个区间的元素个数,当然线段树!
/*
* hdu-1394 minimum inversion number
* mike-w
* 2011-11-25
* ---------------------------------
* reckon with this:
* contains a permutation of the n integers from 0 to n-1.
* tip:
* 线段树坐标的范围不一定从1开始,可以从0开始——学习了!
*/
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<assert.h>
#define MAX_N 5050
#define TREE_SIZE (4*MAX_N)
typedef struct x_snode
{
int l,r,num;
}snode;
snode tree[TREE_SIZE];
int a[MAX_N];
int N;
int build(int root,int l,int r)
{
tree[root].l=l;
tree[root].r=r;
tree[root].num=0;
if(l==r) return 0;
int mid=(l+r)/2;
build(2*root,l,mid);
build(2*root+1,mid+1,r);
return 0;
}
int insert(int root,int x)
{
tree[root].num++;
if(tree[root].l==tree[root].r)
return 0;
int mid=(tree[root].l+tree[root].r)/2;
if(x<=mid)
insert(root*2,x);
else
insert(root*2+1,x);
return 0;
}
int search(int root,int l,int r)
{
if(l>r) /* do NOT omit this case */
return 0;
if(l==tree[root].l && tree[root].r==r)
return tree[root].num;
int mid=(tree[root].l+tree[root].r)/2;
if(r<=mid)
return search(root*2,l,r);
else if(l>mid)
return search(root*2+1,l,r);
else
return search(root*2,l,mid) + search(root*2+1,mid+1,r);
}
int main(void)
{
#ifndef ONLINE_JUDGE
assert(freopen("in","r",stdin));
#endif
int i,tmp,total,ans;
while(scanf("%d",&N)!=EOF)
{
for(i=1;i<=N;i++)
scanf("%d",a+i);
total=0;
build(1,0,N-1);
for(i=1;i<=N;i++)
{
total+=search(1,a[i]+1,N-1);
insert(1,a[i]);
}
ans=total;
for(i=1;i<=N;i++)
{
total+=N-2*a[i]-1;
if(total<ans)
ans=total;
}
printf("%d\n",ans);
}
return 0;
}