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

 

posted @ 2020-02-16 22:33  zlc0405  阅读(78)  评论(0编辑  收藏  举报