HDOJ1394(线段树-单点更新)

注:本题运用线段树只是用于第一次求逆序数,降低时间复杂度。至于后面的筛选,用的是逆序数的一个性质,就是两相邻数字交换位置,逆序数+1或者-1.

    /* 
    HDOJ1754 
    作者:陈佳润 
    时间:2013-03-29 
    */  
    #include<iostream>  
    using namespace std;  
    #define MaxSize 5001  
    int Tree[MaxSize*4];  
    //计算父节点  
    void PushUp(int p)  
    {  
        Tree[p]=Tree[p<<1]+Tree[p<<1|1];  
    }  
    //创建线段树  
    void Create(int p,int l,int r){//可存在[a,a]的节点  
        Tree[p]=0;//初始化,如果有用下面的语句读入,则无需  
        if(l==r){//当达到叶子节点时  
              //scanf("%d",&Tree[p]);//当需要读的时候   
              return;  
         }  
         int mid=(l+r)>>1;//计算中间值  
         Create(p<<1,l,mid);//向左递归  
         Create(p<<1|1,mid+1,r);//向右递归  
         //PushUp(p);//计算节点值  
    }  
    //修改线段树  
    void Add(int i,int add,int p,int l,int r){//增加叶子节点数值  
         if(l==r){//当达到叶子节点时,加上修改值  
              Tree[p]+=add;  
              return ;  
         }  
         int mid=(l+r)>>1;//计算中间值  
         if(i<=mid)//向左递归  
              Add(i,add,p<<1,l,mid);  
         else//向右递归  
              Add(i,add,p<<1|1,mid+1,r);  
         PushUp(p);//计算节点值  
    }  
    //查询线段树  
    int Query(int p,int l,int r,int L,int R){  
         if(R>=r&&L<=l)//当查询的区间比树的区间大时  
              return Tree[p];  
         int sum=0;//当前节点的值  
         int mid=(l+r)>>1;//计算中间值  
         if(L<=mid)//向左递归  
              sum+=Query(p<<1,l,mid,L,R);  
         if(R>mid)//向右递归  
              sum+=Query(p<<1|1,mid+1,r,L,R);  
         return sum;  
    }  
    int main()  
    {  
       
        int n,i,a[MaxSize],sum,ret;  
        while(scanf("%d",&n)!=EOF){  
            Create(1,0,n-1);  
            sum=0;  
            for(i=0;i<n;i++){  
                scanf("%d",&a[i]);  
                sum+=Query(1,0,n-1,a[i],n-1);  
                Add(a[i],1,1,0,n-1);  
            }  
            ret=sum;  
            for(i=0;i<n;i++){  
                sum+=(n-1)-a[i]-a[i];  
                if(ret>sum)  
                    ret=sum;  
            }  
            cout<<ret<<endl;  
        }  
    }  


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值