/* 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; }