hdu1394逆序数(线段树)

题目链接http://acm.hdu.edu.cn/showproblem.php?pid=1394

题目大意:逆序数:即假设在数组a中,假如i<j,但是a[i]>a[j]。

现在有一个数组,含有n个数(为0-(n-1)的一个排列),依次把第一个数,放到数组最后面,求其中逆序数数目最小是多少?

例:

Sample Input
10 1 3 6 9 0 8 5 7 4 2
 
Sample Output
16

解题思路:首先,我们要思考对于一个数组怎样求出它的逆序数的总个数,这里有两种方法,最简单的是,直接暴力,两层循环就可以搞定。这里主要讲一下第二种方法,用线段树也可以很巧妙的求它的逆序数个数,我们先建立一颗空树,然后一个一个将节点插入树中,我们把数组中数的大小看成在树中的位置,然后每插入一个节点,就统计大于这个数的数目,即产生的逆序数的数目,然后再更新该位置的数值为1.这样就求出了初始状态下的逆序数sum了。

然后要求出最小的逆序数,因为数组是0到n-1的一个排列,所以如果当你把第一个数从第一个放到最后一个的时候,逆序数就会减少a【i】个,同时增加n-(a[i]+1)个。所以我们只需要枚举依次把第一个数放到最后位置,所产生的逆序数sum+(n-2*num[i]-1)取最小值即可。

附上代码

暴力解法

#include<iostream>
using namespace std;
#define inf 0x3f3f3f3f
int n,a[5005];

int main()
{
    while(~scanf("%d",&n))
    {
        for(int i=1;i<=n;i++)
            scanf("%d",&a[i]);
        int sum=0;
        for(int i=1;i<=n;i++)
        {
            for(int j=i+1;j<=n;j++)
            {
                if(a[i]>a[j])
                    sum++;
            }
        }
        int ans=inf;
        for(int i=1;i<=n;i++)
        {
            sum+=(n-2*a[i]-1);
            ans=min(ans,sum);
        }
        printf("%d\n",ans);
    }
    return 0;
}

线段树解法

#include<iostream>
#include<cstring>
using namespace std;
#define ll long long
#define maxn 10005
#define lson l,mid,root<<1
#define rson mid+1,r,root<<1|1
#define pushup() tree[root]=tree[root<<1]+tree[root<<1|1]
int n,tree[maxn<<2],num[maxn<<2];

/*
void pushdown(int l,int r,int root)
{
    if(add[root])
    {
        add[root<<1]=add[root];
        add[root<<1|1]=add[root];
        tree[root<<1]=l*add[root];
        tree[root<<1|1]=r*add[root];
        add[root]=0;
    }
}
void build(int l,int r,int root)
{
    add[root]=0;
    if(l==r)
    {
        tree[root]=num[tot++];
        return;
    }
    int mid=l+r>>1;
    build(lson);
    build(rson);
    pushup();
}*/
void update(int pos,int val,int l,int r,int root)
{
    if(l==r)
    {
        tree[root]=val;
        return;
    }
    int mid=l+r>>1;
    if(pos<=mid)
        update(pos,val,lson);
    else
        update(pos,val,rson);
    pushup();
}
int query(int L,int R,int l,int r,int root)
{
    if(L<=l&&R>=r)
        return tree[root];
    int ans=0,mid=l+r>>1;
    if(L<=mid)
        ans+=query(L,R,lson);
    if(R>mid)
        ans+=query(L,R,rson);
    return ans;
}

int main()
{
    while(~scanf("%d",&n))
    {
        memset(tree,0,sizeof(tree));//初始时,为空树,直接memset
        int sum=0;
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&num[i]);
            sum+=query(num[i]+1,n,1,n,1);
            update(num[i]+1,1,1,n,1);
        }
        int ans=sum;
        for(int i=1;i<=n;i++)
        {
            sum+=(n-2*num[i]-1);
            ans=min(ans,sum);
        }
        printf("%d\n",ans);
    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/zjl192628928/p/9693188.html
今日推荐