/*
HDU1394 利用线段树求逆序对数
方法:
从1……n插入每个数,每插入一个数,计算当前线段树中数为a[i]+1....maxval的数有多少个,特别需要当心a[i]+1有可能大于maxval的情况
交换两个相邻数,逆序数+1或-1, 交换两个不相邻数a, b, 逆序数+=两者间大于a的个数-两者间小于a的个数
对于本题,可以假设在第n+1个位置上有一个数n,每次将第一个数与第n+1位置上的n互换
逆元对数 = 原逆元对数 - 比该位置数小的个数 + 比该位置大的个数
*/
//4673112 2011-09-28 18:46:40 Accepted 1394 78MS 240K 1470 B G++ nkhelloworld
//4673116 2011-09-28 18:47:06 Accepted 1394 46MS 280K 1470 B C++ nkhelloworld
#include <cstdio>
#define MAXN 5000
struct SEGMENTTREE
{
int lt,rt,val;
}tree[MAXN*4];
int n,a[MAXN+1];
void buildsegtree(int root,int lt,int rt)
{
tree[root].lt = lt; tree[root].rt = rt; tree[root].val = 0;
if(lt == rt) return ;
int mid = (lt+rt)>>1;
buildsegtree(root<<1,lt,mid);
buildsegtree(root<<1|1,mid+1,rt);
}
int query(int root,int lt,int rt)
{
if(tree[root].lt == lt && tree[root].rt == rt)
return tree[root].val;
int mid = (tree[root].lt + tree[root].rt)>>1;
if(rt <= mid)
return query(root<<1,lt,rt);
if(lt>mid)
return query(root<<1|1,lt,rt);
return query(root<<1,lt,mid) + query(root<<1|1,mid+1,rt);
}
void update(int root,int pos)
{
tree[root].val ++;
if(tree[root].lt == tree[root].rt)
return ;
int mid = (tree[root].lt + tree[root].rt)>>1;
if(pos <= mid)
update(root<<1,pos);
else
update(root<<1|1,pos);
}
int main()
{
int i,sum,minn;
while(scanf("%d",&n)!=EOF)
{
sum = 0;
buildsegtree(1,0,n-1);
for(i=1;i<=n;i++)
{
scanf("%d",&a[i]);
sum += query(1,a[i],n-1);
update(1,a[i]);
}
minn = sum;
for(i=1;i<=n;i++)
{
sum = sum - a[i] + (n - a[i] - 1);
if(sum < minn) minn = sum;
}
printf("%d\n",minn);
}
return 0;
}
转载于:https://www.cnblogs.com/nkhelloworld/archive/2011/09/28/2194736.html