HDU1394 Minimum Inversion Number
线段树单点更新~
用线段树计算总逆序对数(其实也可以树状数组,练习一下线段树的写法,还是很不熟练,线段树在区间修改查询这一块的能力是统治级的~)
然后每操作一次,减去它的比它大的数的数量,再加上比它小的数的数量,与Min比较取最小,最后的Min就是答案~
#include<cstdio> #include<algorithm> #include<cstring> using namespace std; const int maxn=10014; typedef long long ll; struct node { int l,r,sum; }segTree[maxn*4]; int a[maxn]; int r[maxn]; int l[maxn]; int num[maxn]; void build (int i,int l,int r) { segTree[i].l=l; segTree[i].r=r; if (l==r) { segTree[i].sum=0; return; } int mid=(l+r)>>1; build(i<<1,l,mid); build(i<<1|1,mid+1,r); segTree[i].sum=segTree[i<<1].sum+segTree[i<<1|1].sum; } void add (int i,int t,int b) { segTree[i].sum+=b; if (segTree[i].l==t&&segTree[i].r==t) return; int mid=(segTree[i].l+segTree[i].r)>>1; if (t<=mid) add(i<<1,t,b); else add(i<<1|1,t,b); } int query (int i,int l,int r) { if (l==segTree[i].l&&r==segTree[i].r) return segTree[i].sum; int mid=(segTree[i].l+segTree[i].r)>>1; if (r<=mid) return query(i<<1,l,r); else if (l>mid) return query(i<<1|1,l,r); else return query(i<<1,l,mid)+query(i<<1|1,mid+1,r); } int main () { int N; while (~scanf("%d",&N)) { build (1,1,maxn); memset (num,0,sizeof(num)); for (int i=1;i<=N;i++) scanf ("%d",&a[i]),a[i],num[i]=a[i]+100; ll ans=0; for (int i=N;i>=1;i--) { r[i]=query(1,1,num[i]-1); ans+=r[i]; add(1,num[i],1); } ll Min=1e18; for (int i=1;i<=N;i++) { ans=ans-a[i]+N-a[i]-1; Min=min(Min,ans); } printf ("%lld\n",Min); } return 0; }