POJ 2299 Ultra-QuickSort(离散化+树状数组求逆序对)

Ultra-QuickSort
Time Limit: 7000MS Memory Limit: 65536K
Total Submissions: 54900 Accepted: 20189

Description

In this problem, you have to analyze a particular sorting algorithm. The algorithm processes a sequence of n distinct integers by swapping two adjacent sequence elements until the sequence is sorted in ascending order. For the input sequence 
9 1 0 5 4 , 

Ultra-QuickSort produces the output 
0 1 4 5 9 . 

Your task is to determine how many swap operations Ultra-QuickSort needs to perform in order to sort a given input sequence. 

Input

The input contains several test cases. Every test case begins with a line that contains a single integer n < 500,000 -- the length of the input sequence. Each of the the following n lines contains a single integer 0 ≤ a[i] ≤ 999,999,999, the i-th input sequence element. Input is terminated by a sequence of length n = 0. This sequence must not be processed.

Output

For every input sequence, your program prints a single line containing an integer number op, the minimum number of swap operations necessary to sort the given input sequence.

Sample Input

5
9
1
0
5
4
3
1
2
3
0

Sample Output

6
0
一题意:
给定了一种排序方式,通过交换相邻的两个元素的位置达到排序的效果,经过一番思考后会发现,一个排好序的队列事实上是一个完全顺序的队列,所以如果我们希望通过交换的方式来达到排序的效果那么对于每个元素来说已定要和他的所有逆序的数交换位置,且发现每次叫唤位置并不会对其他逆序对发生变化(因为交换的只是相邻元素,位置的改变只发生在这两者之间),所以我们推断出需要交换的总次数就是逆序对的数量。
二用树状数组求逆序对
思路很简单,逆序对就是一个元素之前的并且比这个元素大数构成的点对,那么用树状数组来统计逆序对我们需要换一个思路,倒着来搞,统计每个元素之后会出现多少个比这元素小的数,具体方法是:我们从字符串的尾部开始把元素x加入到树状数组位置x,中并赋值1,然后再通过树状数组的强项求和来统计一个元素之后有多少比他小的数,就是逆序对啦
三数据的离散化
因为树状数组要有位置x,所以我们需要把树状数组的大小开到和x的上限一样大,但是本题中上线回达到999,999,999,但是只有50000个不同的数字,浪费的大量空间和时间不说,也开不了这么大啊,所以我们使用离散化的思想,把这500000个不同的数的数值都压缩到500000中来(因为我们并不关心这个数据到底是多少,只关心他们之间的大小关系),我们利用一个结构来保存原来的位置(复原时用到)和原值(排序时用到),然后根据val来排序,然后把排序的序号当做其值放在val中,然后根据pos再复原到reflect中就可以了
//
//  main.cpp
//  POJ 2299
//
//  Created by 张嘉韬 on 16/8/3.
//  Copyright © 2016年 张嘉韬. All rights reserved.
//

#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll;
const int maxn=500000+10;
ll  c[maxn];
int reflect[maxn];
struct Node
{
    int val;
    int pos;
}Nodes[maxn];

bool cmp(const Node& a, const Node& b)
{
    return a.val < b.val;
}

inline ll lowbit(ll  x)
{
    return (x&-x);
}
ll  sum(ll x)
{
    ll temp=0;
    for(ll  i=x;i;i-=lowbit(i))
        temp+=c[i];
    return temp;
}
void add(ll x,int value)
{
    for(ll i=x;i<=maxn;i+=lowbit(i))
        c[i]+=value;
}
int main(int argc, const char * argv[]) {
    //freopen("/Users/zhangjiatao/Documents/暑期训练/input.txt","r",stdin);
    int n;
    while(scanf("%d",&n)==1)
    {
        if(n==0) break;
        memset(c,0,sizeof(c));
        memset(reflect,0,sizeof(reflect));
        ll  ans=0;
        
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&Nodes[i].val);
            Nodes[i].pos=i;
        }
        
        sort(Nodes + 1, Nodes + n + 1, cmp);
        for(int i=1;i<=n;i++) reflect[Nodes[i].pos]=i;
        for(int i=n;i>=1;i--)
        {
            ans+=sum(reflect[i]+1);
            add(reflect[i]+1,1);
        }
        printf("%lld\n",ans);
    }
    return 0;
}


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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值