专题二树形结构 N - Ultra-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.InputThe 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.OutputFor 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 Output
    5
    9
    1
    0
    5
    4
    3
    1
    2
    3
    0
    
    6
    0
    
  2. 思路
    题目直接把快速排序的名字糊脸上了,这暗示我们......肯定不能用快排,更不能真去跑模拟,必定超时
    根据相关知识,题目可以转化为求逆序对的数量(我对此的理解是,排序的本质就是把所有逆序对反过来),网上看到了归并排序的解法,方法是在合并两个有序子集的时候,对后面一个子集的每个数,统计前一个子集里面比它大的数的个数,每次结果加起来
    不过我们是在训练树状数组,这题当然也有用树状数组做的办法。对数据进行离散化(从大到小排个序编号),然后按从小到大的顺序把后面的数移到前面,统计移动次数。线段树维护的序列是一个全为1的序列,从1到n的和再减去1,就可以代表原来编号为n的数移到相应位置的交换次数(减1是因为序列第n个元素本身也被初始化成1了,统计的时候减去,因为显然一个数不可能自己和自己交换)。交换之后把原来的序列第n个元素改成0(代表移动过了)然后更新即可。当然也可以先把第n个元素改成0更新了再求1到n的和,就不用另外减去1。
    此外因为这个序列本身全是1,修改只改成0,没啥记录的必要,所以可以不用真把这个序列初始化出来,建树的时候直接把最底层的节点值设为1就可以了。
  3. 代码
    #include<cstdio>
    #include<iostream>
    #include<string>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    
    #define Clear(a) memset(a,0,sizeof(a))
    #define MAXN 500005
    
    struct node
    {
    	int v,index;
    }num[MAXN];
    
    int t[MAXN*4];//树
    int n;
    
    int cmp(node i, node j)
    {
        return i.v < j.v;
    }
    
    void build(int p, int l, int r) {
    	if (l == r) {
    		t[p] = 1;
    	    return;
    	}
    	int m = l + ((r - l) >> 1);
    	build(p << 1, l, m), build(p << 1 | 1, m + 1, r);
    	t[p] = t[p << 1] + t[p << 1 | 1];
    }
    
    void change(int p, int l, int r, int in)//in:索引编号
    {
        if(r==l)
    	{
    		t[p] = 0;
    		return;
    	}
        int m = l + ((r - l) >> 1);
        if(in <= m) change(p << 1, l, m, in);
        else change(p << 1 | 1, m + 1, r, in);
    	t[p] = t[p << 1] + t[p << 1 | 1];
    }
    
    int search(int p, int l, int r, int L, int R)//大写的是查询区间
    {
        if(L<=l && r<=R) return t[p];
        int m = l + ((r - l) >> 1);
        int ans = 0;
        if(L <= m) ans += search(p << 1, l, m, L, R);
        if(R > m) ans += search(p << 1 | 1, m + 1, r, L, R);
        return ans;
    }
    
    int main()
    {
        while(scanf("%d", &n) != EOF && n)
        {
            Clear(t); Clear(num);
            for(int i = 1; i <= n; i++)
            {
                scanf("%d", &num[i].v);
                num[i].index = i;
            }
    		build(1, 1, n);
            sort(num+1, num+n+1, cmp);
            long long ans = 0;
            for(int i = 1; i <= n; i++)
            {
                ans += search(1, 1, n, 1, num[i].index) - 1;
                change(1, 1, n, num[i].index);
            }
            printf("%lld\n", ans);
        }
        return 0;
    }
posted @ 2022-02-07 00:02  Benincasa  阅读(28)  评论(0编辑  收藏  举报