• UVA10810 UltraQuickSort 树状数组+离散化 / 归并排序


    Problem B: Ultra-QuickSort

    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.

    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.

    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

    Output for Sample Input

    6
    0  
      该题题意是给定一个数组,求出这个数组的逆序对,题目很经典。写了三个不同的算法,第一个是两重循环写法,地球人都知道的。第二种写法就是立神首先写出来的树状数组加离散了,
    由于题中最多只有500,000个数据,直接将数据附加一个进入时间的标记,然后按照数据的大小进行排序,这也就是一个离散化的过程,数据中最小的数就华丽变身为下标1,最大的数变身为
    N,中间的数依次赋值。最后在扫描一次数组,根据它的原先记录的顺序把离散化之后的值存储起来,比如 9 1 0 5 4 就会变成 5 2 1 4 3 了,再求这个序列的逆序对。这里又用到了树状数
    组了,每次插入一个数,询问一次在它后面的数有多少个(实际上是计算前面有多少个,再拿当前个数减去比它小的数就可以了)。
      代码如下:
     
     1 #include <cstdlib>
    2 #include <cstring>
    3 #include <cstdio>
    4 #include <algorithm>
    5 using namespace std;
    6
    7 struct Node
    8 {
    9 int pos, val;
    10 inline bool operator < ( const Node &t ) const
    11 {
    12 return val < t.val;
    13 }
    14 }e[500005];
    15
    16 int rec[500005], sum[500005];
    17
    18 inline int lowbit( int x )
    19 {
    20 return x & -x;
    21 }
    22
    23 inline void update( int x, int N )
    24 {
    25 while( x <= N )
    26 {
    27 sum[x]++;
    28 x += lowbit( x );
    29 }
    30 }
    31
    32 inline int ss( int x )
    33 {
    34 int ans = 0;
    35 while( x >= 1 )
    36 {
    37 ans += sum[x];
    38 x -= lowbit( x );
    39 }
    40 return ans;
    41 }
    42
    43 int main()
    44 {
    45 int N, M = 500004;
    46 while( scanf( "%d", &N ), N )
    47 {
    48 long long ans = 0;
    49 memset( sum, 0 , sizeof( sum ) );
    50 M = N;
    51 for( int i = 1; i <= N; ++i )
    52 {
    53 scanf( "%d", &e[i].val );
    54 e[i].pos = i;
    55 }
    56 sort( e + 1, e + N + 1 );
    57 for( int i = 1; i <= N; ++i )
    58 {
    59 rec[e[i].pos] = i;
    60 }
    61 for( int i = 1; i <= N; ++i )
    62 {
    63 update( rec[i], N );
    64 ans += i - ss( rec[i] );
    65 }
    66 printf( "%lld\n", ans );
    67 }
    68 }

      第二种写法就是归并排序来进行计算了,首先明确一个观点,就是求某个区间针对一个数的逆序对时,这个区间内的数的排列如何是没有影响的。这为分治法提供了依据,因为如果这个某个区间 a[ i ... j ] 已经有序的话,那么就很好办了,如果一个数 a[N] 比后面的一个数 a[M]大的话,那么逆序对数就直接是区间长度 j - i + 1 减去 N前面的数的总数 N - i + 1。 归并算法就能够很好的解决这个问题。

      代码如下:

     1 #include <cstdio>
    2 #include <cstdlib>
    3 #include <cstring>
    4 #define MAX 500001
    5 using namespace std;
    6
    7 int a[MAX], b[MAX];
    8
    9 long long ans;
    10
    11 void merge( int l, int m, int r )
    12 {
    13 int p = 0, i = l, j = m + 1;
    14 while( i <= m && j <= r )
    15 {
    16 if( a[i] > a[j] )
    17 {
    18 b[p++] = a[j++];
    19 ans += m - i + 1;
    20 }
    21 else
    22 b[p++] = a[i++];
    23 }
    24 while( i <= m ) b[p++] = a[i++];
    25 while( j <= r ) b[p++] = a[j++];
    26 for( int i = 0; i < p; ++i )
    27 a[l+i] = b[i];
    28 }
    29
    30
    31 void Mergesort( int l, int r )
    32 {
    33 if( l < r )
    34 {
    35 int m = ( l + r ) / 2;
    36 Mergesort( l, m );
    37 Mergesort( m + 1, r );
    38 merge( l, m, r );
    39 }
    40 }
    41
    42
    43 int main( )
    44 {
    45 int N;
    46 while( scanf( "%d", &N ), N )
    47 {
    48 ans = 0;
    49 for( int i = 0; i < N; ++i )
    50 scanf( "%d", &a[i] );
    51 Mergesort( 0, N - 1 );
    52 printf( "%lld\n", ans );
    53 }
    54 return 0;
    55 }
  • 相关阅读:
    暑假周总结六
    常用的Linux操作
    大数据概述
    实验一
    我对编译原理的看法
    ActiveReports中自定义Winforms的Viewer 工具栏
    ActiveReport 同一单元格内图片跟文字按条件显示
    ActiveReports最终报表设计器本地化方法介绍
    ActiveReports中如何使用Excel数据源
    如何设置WebViewer的参数栏显示状态
  • 原文地址:https://www.cnblogs.com/Lyush/p/2168749.html
Copyright © 2020-2023  润新知