zoukankan      html  css  js  c++  java
  • hdu 1394 Minimum Inversion Number(线段树 单点更新)

    题目链接:

    http://acm.hdu.edu.cn/showproblem.php?pid=1394

    题目大意:

    给由0-n-1这n个数构成的n个数,定义一个逆序数(前面的比后面的大的数的个数)。把第一个数移到最后的位置,得到一个新的序列,得到一个新的逆序数。一共可以移动n-1次,得到n个逆序数,问这n个逆序数最小的是多少。

    解题思路:

    1、先求出第一个序列的逆序数。

          根据题目特点,建立一个0——(n-1)的线段树,每个区间保存含有当前区间内数的个数。

          对每一个数,查找该数到n-1内已存在数的个数,(因为该数前面的所有数都压到线段树里面去了),再把该数压进去。

         把每个数前面的逆序数加起来,就可以构造出整个逆序数。

    2、当把第一个移到最后时,后面有0——(save[1]-1)一共save[1]个数比save[i]小,共有n-1-save[1]个数比save[1]大

         所以得到递推公式,sum=sum-save[i]+(n-1-save[i])。

    代码:

    #include<iostream>
    #include<cmath>
    #include<cstdio>
    #include<cstdlib>
    #include<string>
    #include<cstring>
    #include<algorithm>
    #include<vector>
    #include<map>
    #include<stack>
    #include<queue>
    #define eps 1e-6
    #define INF (1<<20)
    #define PI acos(-1.0)
    using namespace std;
    #define lson l,m,rt<<1
    #define rson m+1,r,(rt<<1)|1
    #define maxn 5100
    
    int sum[4*maxn],save[maxn];
    
    void build(int l,int r,int rt)
    {
        sum[rt]=0;  //表示该区间一共有多少个数
        if(l==r)
            return ;
        int m=(l+r)>>1;
    
        build(lson);
        build(rson);
        return ;
    }
    
    int query(int L,int R,int l,int r,int rt)
    {
        if(L<=l&&R>=r)  //如果要找区间大于当前区间,直接返回当前区间
            return sum[rt];
        int m=(l+r)>>1,temp=0;
    
        if(R<=m)
            return query(L,R,lson);
        else if(L>m)
            return query(L,R,rson);
        else
        {
            temp+=query(L,R,lson);
            temp+=query(L,R,rson);
            return temp;
        }
    
    }
    
    void pushup(int rt)  //向上更新,每次插入的时候向上更新,注意是覆盖
    {
        sum[rt]=sum[rt<<1]+sum[rt<<1|1];
    }
    void update(int target,int l,int r,int rt)
    {
        if(l==r)
        {
            sum[rt]++;
            return ;
        }
    
        int m=(l+r)>>1;
    
        if(target<=m)
            update(target,lson);
        else
            update(target,rson);
    
        pushup(rt);
        return ;
    }
    
    
    int main()
    {
        int n,temp;
    
        while(scanf("%d",&n)!=EOF)
        {
            int sum=0;
    
            build(0,n-1,1);  //注意区间是0-(n-1)
            for(int i=1;i<=n;i++)
            {
                scanf("%d",&save[i]);
                sum+=query(save[i],n-1,0,n-1,1);
                update(save[i],0,n-1,1);
            }
    
            int ans=sum;
    
            for(int i=1;i<n;i++)
            {
                sum+=n-2*save[i]-1;
                ans=min(sum,ans);
            }
            printf("%d\n",ans);
        }
    
        return 0;
    }
    
    
    
    


     

  • 相关阅读:
    「消息队列」看过来!
    stl中map的四种插入方法总结
    4.shell编程-文本处理三剑客之sed
    3.shell编程-文件查找之find命令
    2.shell编程-函数的高级用法
    1.shell编程-变量的高级用法
    Django打造大型企业官网(八)
    Django打造大型企业官网(七)
    Django打造大型企业官网(六)
    Django打造大型企业官网(五)
  • 原文地址:https://www.cnblogs.com/javawebsoa/p/2990557.html
Copyright © 2011-2022 走看看