• POJ 2299 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.

    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

    给你一个排序,让你求出这个排序中的逆序数.算是自己写的树状数组的第一道题吧,这个题首先用到离散化思想.
    因为每个数都是小于1e9,而n的范围不超过5e5,而且我们只关心这些数的大小关系,所以我们就把这些数全部映射到1~n,然后再按照排好序的位置插进去就行了
    这样子是不会影响最后算逆序数的.映射后的序列为reflect
    接下来求逆序数,这时要用到树状数组,树状数组的功能是用来求数组前缀和的,我们假想有一个长度为n的数组,它现在每一位初始化为0
    我们按照位置顺序将reflect中的每一个数插入到树状数组中,假设我们现在插入的数是第i个数,它的值为x
    那么我就把刚刚假想的数组的第x位置变为1,即代表x被插入到该序列
    那么每一次对于ans怎样+呢?
    我们可以定义sum(x) x及小于x的数中有多少个元素已经被插入
    这样的话sum(x)就是我们刚刚那个假想数组的前缀和了,我们用树状数组可以求
    对于插入的第i个数,我们的ans+=i-sum(x),因为x是第i个数插进来的,之前插进来小于等于x的数为sum(x)
    两者做差就是在x之前插入,而且值要大于x的数字的个数
    代码如下:
     1 #include <cstdio>
     2 #include <cstring>
     3 #include <cmath>
     4 #include <algorithm>
     5 using namespace std;
     6 const int maxn =550000;
     7 int reflect[maxn];
     8 int c[maxn];
     9 int n;
    10 int lowbit (int x)
    11 {
    12     return x&(-x);
    13 }
    14 struct Node
    15 {
    16     int val,pos;
    17 };
    18 Node node[maxn];
    19 bool cmp (Node q1,Node q2)
    20 {
    21     return q1.val<q2.val;
    22 }
    23 
    24 void update (int x)
    25 {
    26     while (x<=n){
    27         c[x]+=1;//将我们想象的数组x位置附为1,直接就加到c[x]上了
    28         x+=lowbit(x);//找父节点
    29     }
    30 }
    31 int getsum (int x)
    32 {
    33     int sum=0;
    34     while (x>0){
    35         sum+=c[x];
    36         /*求和时可以看作将x用二进制表示
    37         temp=x;
    38         每次加上c[temp],再把temp最后1位置上的值改成0
    39           最后变成0时就求完了
    40           如:求 101001
    41            temp=101001 ->  sum+=c[101001]
    42         -> temp=101000 ->  sum+=c[101000]
    43         -> temp=100000 ->  sum+=c[100000]
    44         -> temp=000000    求完了
    45         */
    46         x-=lowbit(x);
    47     }
    48     return sum;
    49 }
    50 int main()
    51 {
    52     //freopen("de.txt","r",stdin);
    53     while (scanf("%d",&n)&&n){
    54         for (int i=1;i<=n;++i){
    55             scanf("%d",&node[i].val);
    56             node[i].pos=i;
    57         }
    58         sort(node+1,node + n + 1, cmp);
    59         for (int i=1;i<=n;++i) reflect[node[i].pos]=i;//离散化映射到1~n
    60         for (int i=0;i<=n;++i) c[i]=0;//初始化树状数组
    61         long long ans=0;
    62         for (int i=1;i<=n;++i){
    63             update(reflect[i]);//插入一个数,更新一下
    64             ans+=i-getsum(reflect[i]);//ans加一下
    65         }
    66         printf("%lld
    ",ans);
    67     }
    68     return 0;
    69 }
     
  • 相关阅读:
    洛谷P1085 不高兴的津津
    为什么要学习算法
    洛谷P1001 A+B Problem
    计算机问题求解周期
    洛谷P1000 超级玛丽游戏
    洛谷P1421 小玉买文具
    CF359D Pair of Numbers(ST+二分)
    2020.10.7
    2020.10.10
    2020.10.8
  • 原文地址:https://www.cnblogs.com/agenthtb/p/6884099.html
Copyright © 2020-2023  润新知