专题二树形结构 N - 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 sequence9 1 0 5 4 ,
Ultra-QuickSort produces the output0 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.
SampleInput Output 5 9 1 0 5 4 3 1 2 3 0
6 0
- 思路
题目直接把快速排序的名字糊脸上了,这暗示我们......肯定不能用快排,更不能真去跑模拟,必定超时
根据相关知识,题目可以转化为求逆序对的数量(我对此的理解是,排序的本质就是把所有逆序对反过来),网上看到了归并排序的解法,方法是在合并两个有序子集的时候,对后面一个子集的每个数,统计前一个子集里面比它大的数的个数,每次结果加起来
不过我们是在训练树状数组,这题当然也有用树状数组做的办法。对数据进行离散化(从大到小排个序编号),然后按从小到大的顺序把后面的数移到前面,统计移动次数。线段树维护的序列是一个全为1的序列,从1到n的和再减去1,就可以代表原来编号为n的数移到相应位置的交换次数(减1是因为序列第n个元素本身也被初始化成1了,统计的时候减去,因为显然一个数不可能自己和自己交换)。交换之后把原来的序列第n个元素改成0(代表移动过了)然后更新即可。当然也可以先把第n个元素改成0更新了再求1到n的和,就不用另外减去1。
此外因为这个序列本身全是1,修改只改成0,没啥记录的必要,所以可以不用真把这个序列初始化出来,建树的时候直接把最底层的节点值设为1就可以了。 - 代码
#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; }