poj 2299 Ultra-QuickSort (离散化,树状数组,逆序对)

小记:看到这题感到莫名的熟悉感,大概是因为蓝桥杯最后一题也是求这样的逆序对吧,而我写的解题报告也是用树状数组实现的。所以直接动手


思路:题意就是求一个序列中的逆序对数,hdu2689和这个题类似(点击看那题的解题报告),只不过这题的数比较大,不能直接对元素数用树状树状,为此我们必须离散化,

离散化是,用一个结构体数组,其保存元素值和次序id:

struct node {
    int num,id;
} a[MAX_];

然后对该数组以元素值从小到大排序,

bool cmp2(const node &a,const node& b) {
    return a.num < b.num;
}

如果某两个数的值是相等的,那么我们就令其为同一个id,

if(a[i].num!=a[i-1].num) b[a[i].id]=i;
else b[a[i].id]=b[a[i-1].id];
保证了元素值与id是互相唯一对应的了,那么就可以对id用树状数组求解了。

对每个元素的id求出其前面大于它id的数的个数,算出总和就是answer了:

for(int i=1; i<=n; i++) {
    add(b[i],1);
    ans+=sum(n)-sum(b[i]);
}


代码:

#include <iostream>
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <stdlib.h>
#include <map>
#include <set>
#include <vector>
#include <stack>
#include <algorithm>

using namespace std;

#define mst(a,b) memset(a,b,sizeof(a))
#define eps 10e-8

const int MAX_ = 500010;
const int INF = 0x7fffffff;
const int MAX = 500010;


struct node {
    int num,id;
} a[MAX_];


int C[MAX_], b[MAX_];
int T, n, m,l ,r;


int lowbit(int x) {
    return x&(-x);
}

void add(int x,int num) {
    while(x < MAX) {
        C[x] += num;
        x += lowbit(x);
    }
}

int sum(int x) {
    int cnt = 0;
    while(x > 0) {
        cnt += C[x];
        x -= lowbit(x);
    }
    return cnt;
}


bool cmp2(const node &a,const node& b) {
    return a.num < b.num;
}

int main() {
    while(scanf("%d",&n),n) {
        for(int i=1; i<=n; i++) {
            scanf("%d",&a[i].num);
            a[i].id = i;
        }
        mst(b,0);
        mst(C,0);
        //离散化
        sort(a+1,a+n+1,cmp2);
        
        b[a[1].id]=1;
        for(int i=2; i<=n; i++) {
            if(a[i].num!=a[i-1].num) b[a[i].id]=i;
            else b[a[i].id]=b[a[i-1].id];
        }
        long long  ans=0;
        
        for(int i=1; i<=n; i++) {
            add(b[i],1);
            ans+=sum(n)-sum(b[i]);
        }
        printf("%I64d\n",ans);
    }
    return 0;
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值