poj2299Ultra-QuickSort【树状数组求逆序数、离散化】、【归并排序模板】

Description

poj2299Ultra-QuickSort【树状数组求逆序数、离散化】、【归并排序模板】_第1张图片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

Source

Waterloo local 2005.02.05

搁浅了好久了树状数组,尤其是在两天都被操作系统虐的不行不行的情况下,捡起本来就不咋熟练的这货还是有些费事。

这次的专题没做裸的树状数组,逆序数算是树状数组里面比较典型的应用了,尤其是500,000的数据量需要用到离散化,啥是离散化?

以这个题为例,手写了一下中间变量的输出:原数组是9,1,0,5,4  离散后变成了5,2,1,4,3大大缩减了空间开销,这里需要着重注意一下~~

再就说道求逆序数的原理:查询函数返回在序列中比这个数小的个数,假定序列中第i个数为a,那么前i个数中比i大的元素个数为i-sum(i)。当然了,求之前需要调用add函数,函数的第一个参数本来是位置,在这个题中当然带进去的也是离散后的相对位置,貌似说的不是特别明白==

用最原始的树状数组来说明,数组A代表数字i在序列中是否出现过,如果已经存在,那么A【i】=1,否则等于0,,此时查询函数返回值为序列中比数字i小的个数。因为是一位一位add进去,增加一个查询一个,出现了一个数x,则a[x]=1,暂时没出现的就是0,查询的是当前这个数以前的,那么答案显而易见啦

/***************
2016.2.1
poj2277
8152K	391MS	G++	1129B
***************/
#include <iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define maxn 500005
int n;
int c[maxn],b[maxn];
struct Node
{
    int index,v;
}node[maxn];
bool cmp(Node a,Node b)
{
    return a.v<b.v;
}
int lowbit(int x)
{
    return x&(-x);
}
void add(int i,int val)
{
    while(i<=n)
    {
        c[i]+=val;
        i+=lowbit(i);
    }
}
int sum(int i)
{
    int s=0;
    while(i>0)
    {
        s+=c[i];
        i-=lowbit(i);
    }
    return s;
}
int main()
{
    //freopen("cin.txt","r",stdin);
    while(~scanf("%d",&n)&&n)
    {
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&node[i].v);
            node[i].index=i;
        }
        memset(b,0,sizeof(b));
        memset(c,0,sizeof(c));
        sort(node+1,node+1+n,cmp);
        b[node[1].index]=1;
        for(int i=2;i<=n;i++)
        {
            b[node[i].index]=i;
        }
        long long ans=0;
        for(int i=1;i<=n;i++)
        {
            add(b[i],1);
            ans+=(i-sum(b[i]));
        }
        printf("%I64d\n",ans);
    }
    return 0;
}


不是自己的代码,但是是裸的应用,没必要再写一遍是吧



#include <stdio.h>
#include<string.h>
#include<iostream>
using namespace std;
const int MAXN=500010;
long long ans;//存放逆序数,比较大,必须用long long
int a[MAXN],b[MAXN],c[MAXN];

//将已经排好序的left~mid,mid+1~right进行归并
void merge(int *a,int left,int mid,int right)
{
    int i,j;
    i=0;
    for(j=left;j<=mid;j++)
       b[i++]=a[j];
    int len1=mid-left+1;
    i=0;
    for(j=mid+1;j<=right;j++)
       c[i++]=a[j];
    int len2=right-mid;
    i=0;
    j=0;
    int k=left;
    while(i<len1&&j<len2&&k<=right)
    {
        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 left,int right)//对a[left~right-1]进行归并排序
{
    if(left<right)
    {
        int mid=(left+right)/2;
        merge_sort(a,left,mid);
        merge_sort(a,mid+1,right);
        merge(a,left,mid,right);
    }
}
int main()
{
    //freopen("in.txt","r",stdin);
    //freopen("out.txt","w",stdout);
    int n;
    while(scanf("%d",&n),n)
    {
        for(int i=0;i<n;i++)
          scanf("%d",&a[i]);
        ans=0;
        merge_sort(a,0,n-1);
        printf("%I64d\n",ans);
    }
    return 0;
}



















你可能感兴趣的:(数据结构,poj)