hdu1394线段树

本文介绍了一种求解最小逆序数排列的算法,通过不断后移首个数字并使用线段树更新逆序数,实现对初始排列的优化。算法详细解释了如何计算逆序数,以及如何通过特定操作达到最小逆序数的目标。

求一个排列的最小逆序数,只能够通过将第一个数字不断后移的方式更改顺序。由于题目给出的数字是0-n-1所以每次将首个数字向后移时都满足(假设逆序数为ans首个数字为a[e])ans加n-1-a[e]个逆序数再减去a[e]个逆序数(数学问题,那么问题就很简单了,先求出初始逆序数,再用公式不断计算,得出最小值。关键在于怎么求初始逆序数。用线段树,每次输入数字,将该数字叶子节点数更新1,并求输入这个数字时前面已有的叶子节点(即首顺序中这个数字前的数字)比该数字大的数不断叠加即可得到逆序数。

#include<iostream>
#include<stdio.h>
#include<algorithm>
using namespace std;
int n,m;
char c[10];
const int maxn=50005;
int node[maxn<<2];
int t[maxn];
void pushup(int nd)
{
    node[nd]=node[nd<<1]+node[nd<<1|1];
}
void build(int l,int r,int nd)
{
    if(l==r)
    {node[nd]=0;
    return;}
    int mid=(l+r)>>1;
    build(l,mid,nd<<1);
    build(mid+1,r,nd<<1|1);
    pushup(nd);
}
void update(int pos,int l,int r,int nd)
{
    if(l==r)
    {
        node[nd]=1;
        return;
    }
    int mid=(l+r)>>1;
    if(mid<pos)update(pos,mid+1,r,nd<<1|1);
    else update(pos,l,mid,nd<<1);
        pushup(nd);
}
int query(int s,int e,int l,int r,int nd)
{
    if(s<=l&&e>=r)
    {
        return node[nd];
    }
    int ans=0;
    int mid=(l+r)>>1;
    if(s<=mid)ans+=query(s,e,l,mid,nd<<1);
    if(e>mid)ans+=query(s,e,mid+1,r,nd<<1|1);
    return ans;
}
int main()
{
        while(cin>>n)
        {  build(0,n-1,1);
        int ans=0;
            for(int i=0;i<n;i++)
            {cin>>t[i];
            ans+=query(t[i]+1,n-1,0,n-1,1);
            update(t[i],0,n-1,1);}
            int minn=ans;
            for(int i=0;i<n-1;i++)
                {
                ans+=n-1-t[i]*2;
                minn=min(minn,ans);
                }
            cout<<minn<<endl;
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值