POJ 2299 Ultra-QuickSort (求逆序数:离散化+树状数组或者归并排序求逆序数)

Ultra-QuickSort

Time Limit: 7000MS   Memory Limit: 65536K
Total Submissions: 55048   Accepted: 20256

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题意:就是求逆序数分析:有几种方法,这里用了两个
#include<stdio.h>
#include<string.h>
#include<iostream>
#include<algorithm>
using namespace std;

const int MAXN = 500010;
int F[MAXN];
int a[MAXN];
int n;
pair<int,int>p[MAXN];
void update(int x,int val)
{
    while(x<=n)
    {
        F[x]+=val;
        x+=x&-x;
    }
}
int query(int x)
{
    int res=0;
    while(x>0)
    {
        res+=F[x];
        x-=x&-x;
    }
    return res;
}

int main()
{
    while(scanf("%d",&n)==1&&n)
    {
        memset(F,0,sizeof(F));
        memset(a,0,sizeof(a));
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&p[i].first);
            p[i].second=i;
        }
        sort(p+1,p+n+1);
        a[p[1].second]=1;
        for(int i=2;i<=n;i++)
        {
            if(p[i].first!=p[i-1].first) a[p[i].second]=i;
            else a[p[i].second]=a[p[i-1].second];
        }
        long long ans=0;
        for(int i=1;i<=n;i++)
        {
            update(a[i],1);
            ans+=query(n)-query(a[i]);
        }
        printf("%lld\n",ans);
    }
    return 0;
}
/*
 用归并排序求逆序数
 */
#include<stdio.h>
#include<string.h>
#include<iostream>
#include<algorithm>
using namespace std;

const int MAXN = 500010;
int a[MAXN],b[MAXN],c[MAXN];
long long ans;

//将已经排好的l-mid,mid+1-r进行归并
void merge(int *a,int l,int mid,int r)
{
    for(int i=0,j=l;j<=mid;j++)
        b[i++]=a[j];
    int len1=mid-l+1;
    for(int i=0,j=mid+1;j<=r;j++)
        c[i++]=a[j];
    int len2=r-mid;
    int i=0,j=0,k=l;
    while(i<len1&&j<len2&&k<=r)
    {
        if(b[i]<=c[j]) a[k++]=b[i++];
        else
        {
            a[k++]=c[j++];
            ans+=len1-i;//逆序数就是累加后面比自己小的数的个数
            //此时b[i]>c[j],那么c[j]会给b[i]后面的len1-i个数造成逆序数
        }
    }
    while(i<len1) a[k++]=b[i++];
    while(j<len2) a[k++]=c[j++];
}
void merge_sort(int *a,int l,int r)
{
    if(l<r)
    {
        int mid=(l+r)/2;
        merge_sort(a,l,mid);
        merge_sort(a,mid+1,r);
        merge(a,l,mid,r);
    }
}

int main()
{
    int n;
    while(scanf("%d",&n)==1&&n)
    {
        for(int i=1;i<=n;i++)
            scanf("%d",&a[i]);
        ans=0;
        merge_sort(a,1,n);
        printf("%lld\n",ans);
    }
    return 0;
}
 
时间: 2024-10-23 02:42:52

POJ 2299 Ultra-QuickSort (求逆序数:离散化+树状数组或者归并排序求逆序数)的相关文章

Codeforces Round #301 (Div. 2) E. Infinite Inversions —— 逆序对 离散化 + 树状数组

题目链接:http://codeforces.com/contest/540/problem/E E. Infinite Inversions time limit per test 2 seconds memory limit per test 256 megabytes input standard input output standard output There is an infinite sequence consisting of all positive integers in

逆序对 (树状数组 | | 归并排序

数组前面的一个元素 大于等于 后面的一个元素就是一个逆序对: 树状数组可以快速求前缀和,利用这一特性,可以求逆序对个数,见下: 用数组c[ i ]记录数组a[ n ]中i这一元素出现的次数 ,当a[ n ]中元素较大时可以离散化处理. 将a[ n ]从a[n -1]到a[0] 依次存到树状数组中,每存一个,对存的元素i求一次c[i]的前缀和, 这就是当前已扫描过的比i小的元素的个数,由于a[n]是倒着扫描的,所以此时比i小的元素都对应一个逆序对,统计之. #include <cstdio> #

poj 2299 Ultra-QuickSort 求逆序数,树状数组解法,详细解析

Ultra-QuickSort Time Limit: 7000MS   Memory Limit: 65536K Total Submissions: 44554   Accepted: 16195 Description In this problem, you have to analyze a particular sorting algorithm. The algorithm processes a sequence of n distinct integers by swappin

POJ 2299 Ultra-QuickSort (离散化+树状数组)

题目链接:POJ 2299 Ultra-QuickSort 求一串序列相邻连个元素交换多少后,是一串上升的序列. 思路:求该串序列的逆序数,数据比较大,要离散化. AC代码: #include<stdio.h> #include<string.h> #include<set> #include<map> #include<algorithm> #define ll __int64 using namespace std; const ll max

poj 2299 Ultra-QuickSort 离散化 + 树状数组

题目链接:http://poj.org/problem?id=2299 离散化 + 树状数组 教科书例题般的题目 #include <iostream> #include <cstdio> #include <cstring> #include <queue> #include <cmath> #include <vector> #include <stack> #include <set> #include

HDU 4417 类似求逆序数的树状数组

Super Mario Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 2250    Accepted Submission(s): 1092 Problem Description Mario is world-famous plumber. His “burly” figure and amazing jumping ability

求逆序对 (树状数组版)

基本思想和线段树求解逆序数是一样的,前一篇<求逆序对 线段树版>也介绍过,先对输入数组离散,数组里的元素都不相同可以直接hash,存在相同的数话可以采用二分. 离散化后对于每个f[i],找到f[i]+1~ n中的个数,也就是到i这个位置,一共有多少比f[i]大的数,统计之后在将f[i]的位置上的数量加1. 这样一来统计的就是类似a[i]~n的和,可以想象成 把树状数组反过来统计,即统计的时候加lowbit,更新的时候减lowbit. 还是 以POJ 2299为例. #include <i

Day2:T4求逆序对(树状数组+归并排序)

T4: 求逆序对 A[I]为前缀和 推导 (A[J]-A[I])/(J-I)>=M A[j]-A[I]>=M(J-I) A[J]-M*J>=A[I]-M*I 设B[]=A[]-M*(); B[J]>=B[I] 也就是求逆序对: 求逆序对的方法主要有两种: 归并排序: 树状数组: 这里两种方法都学习一下: 1.之前对于树状数组的印象就只有单点修改和区间求和 一直觉得lowbit是一个神奇的东西(至今没有搞懂原理) 上网搜了一下用树状数组求逆序对的方法,发现有一个大神写的很棒....看

CodeForces 540E - Infinite Inversions(离散化+树状数组)

花了近5个小时,改的乱七八糟,终于A了. 一个无限数列,1,2,3,4,...,n....,给n个数对<i,j>把数列的i,j两个元素做交换.求交换后数列的逆序对数. 很容易想到离散化+树状数组,但是发现那些没有交换的数也会产生逆序对数,但我没有算. 经明神提示, 把没有用到的数字段化成点.然后用树状数组算一下就好了. 然后我用一个数组记录每个点的长度.比如 <1,2><5,6>,1,2,3,4,5,6只有1,2,5,6用到了,那么离散化为1,2,3,4,5,f[1]=