HDU 1394 Minimum Inversion Number(线段树求逆序数)

来源:互联网 发布:java分等级并统计个数 编辑:程序博客网 时间:2024/05/22 10:23

题目地址:HDU 1394

这题可以用线段树来求逆序数。

这题的维护信息为每个数是否已经出现。每次输入后,都从该点的值到n-1进行查询,每次发现出现了一个数,由于是从该数的后面开始找的,这个数肯定是比该数大的。那就是一对逆序数,然后逆序数+1.最后求完所有的逆序数之后,剩下的就可以递推出来了。因为假如目前的第一个数是x,那当把他放到最后面的时候,少的逆序数是本来后面比他小的数的个数。多的逆序数就是放到后面后前面比他大的数的个数。因为所有数都是从0到n-1.所以比他小的数就是x,比他大的数就是n-1-x。这样的话每次的逆序数都可以用O(1)的时间计算出来。然后找最小的时候就可以了。

代码如下:

#include <iostream>#include <cstdio>#include <cstring>#include <math.h>#include <stack>using namespace std;#define lson l, mid, rt<<1#define rson mid+1, r, rt<<1|1const int MAXN=6e3;int sum[MAXN<<2], a[MAXN];void PushUp(int rt){    sum[rt]=sum[rt<<1]+sum[rt<<1|1];}void build(int l, int r, int rt){    sum[rt]=0;    if(l==r)    {        return ;    }    int mid=l+r>>1;    build(lson);    build(rson);}void update(int p, int l, int r, int rt){    if(l==r)    {        sum[rt]++;        return ;    }    int mid=l+r>>1;    if(p<=mid) update(p,lson);    else update(p,rson);    PushUp(rt);}int query(int ll, int rr, int l, int r, int rt){    if(ll<=l&&rr>=r)    {        return sum[rt];    }    int mid=l+r>>1;    int ans=0;    if(ll<=mid) ans+=query(ll,rr,lson);    if(rr>mid) ans+=query(ll,rr,rson);    return ans;}int main(){    int n, i, ans, y;    while(scanf("%d",&n)!=EOF)    {        build(0,n-1,1);        ans=0;        for(i=0; i<n; i++)        {            scanf("%d",&a[i]);            ans+=query(a[i],n-1,0,n-1,1);            update(a[i],0,n-1,1);        }        y=ans;        for(i=0;i<n;i++)        {            y+=n-1-2*a[i];            ans=min(ans,y);        }        printf("%d\n",ans);    }    return 0;}


0 0