逆序对(hdu2838)

题目概述:
给定一个序列,交换其中两个元素x,y的代价是x+y,求将一个序列变成单调不减的序列的最小代价。
题目思路:
把一个小的从后面移到前面,需要和前面所有比他大的交换,而大的移到后面则需要和后面所有比他小的交换。所以就是正着求一次每个数在当前序列的位置和倒着求一次。最后乘这个元素然后加到结果里。
当然其实就是求逆序对数,用线段树,用类似归并排序,用树状数组都可以。。。。

一开始想用treap写的,不过左旋和右旋大数据的时候老是RE,所以果断将其退化成二叉搜索树。

代码:

#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<time.h>

using namespace std;

struct treap
{
    treap *l,*r;
    int v,f,s;
    inline int ls()
    {
        return l?l->s:0;
    }
    inline int rs()
    {
        return r?r->s:0;
    }
};

int a[100010];

treap* treapinsert(treap *a,int v)
{
    if (!a)
    {
        a=(treap*)malloc(sizeof(treap));
        a->v=v;
        a->f=rand();
        a->l=0;
        a->r=0;
        a->s=1;
    }
    else if (v<=a->v)
    {
        a->s++;
        a->l=treapinsert(a->l,v);
    }
    else
    {
        a->s++;
        a->r=treapinsert(a->r,v);
    }
    return a;
}

int treaprank(treap *a,int v,int cur)
{
    if (a&&v==a->v) return a->ls()+cur+1;
    else if (a&&v<=a->v)
        return treaprank(a->l,v,cur);
    else if (a)
        return treaprank(a->r,v,cur+a->ls()+1);
    else return 0;
}

int main()
{
    srand(time(0));
    int n;
    cin>>n;
    for (int i=1;i<=n;i++) scanf("%d",&a[i]);
    long long ans=0;
    treap *root=0;
    for (int i=1;i<=n;i++)
    {
        root=treapinsert(root,a[i]);
        ans+=(long long)a[i]*(i-treaprank(root,a[i],0));
    }
    free(root);
    treap *rooot=0;
    for (int i=n;i>=1;i--)
    {
        rooot=treapinsert(rooot,a[i]);
        ans+=(long long)a[i]*(treaprank(rooot,a[i],0)-1);
    }
    free(rooot);
    cout<<ans<<endl;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值