PKU 2299 求解逆序数(使用归并或者树状数组) 树状数组及入门知识
2013-01-11 15:41
323 查看
归并ac代码为:
树状数组主要是这张图片:
Lowbit(x),是求出2^p(其中p为x的二进制表示中最右边的那个1的位置),如6的二进制表示为110,最右边的1为1,故Lowbit(6) = 2^1 = 2。
Update(x, c),是使x这点的值改变c,如果是一般数组改变的就是x自己这点,但是树状数组中要把(x, x+Lowbit(x), x+Lowbit(x+Lowbit(x))),…)这条路径的点都要改变c,这样做是为了后面能够高效地求和。(注意x的值可能是实际的值,也可能是数组的下标,如果太大的话需要离散化)
Getsum(x), 是求的(1, …x-Lowbit(x-Lowbit(x))), x-Lowbit(x), x)这条路径的点的和,换句话说就相当于求一般数组a[1]到a[x]的和。
树状数组的高效就在于: 与一般数组不同,一般数组都是下标不断加一来遍历的,而树状数组是不断加2^p来变化的,故效率为(logn)级别的。
树状数组的最基本功能就是求比某点x小的点的个数(这里的比较是抽象的概念,可以使数的大小,坐标的大小,质量的大小等)。
比如给定个数组a[5] = {2, 5, 3, 4, 1},求b[i] = 位置i左边小于等于a[i]的数的个数.如b[5] = {0, 1, 1, 2, 0},这是最正统的树状数组的应用,直接遍历遍数组,每个位置先求出Getsum(a[i]),然后再修改树状数组Update(a[i], 1)即可。当数的范围比较大时需要进行离散化,即先排个序,再重新编号。如a[] = {10000000, 10, 2000, 20, 300},那么离散化后a[] = {5, 1, 4, 2, 3}。(本题就是这个例子)
详细资料:http://download.csdn.net/detail/vsooda/4985249
#include <iostream> #include <fstream> using namespace std; #define MAX 500005 int a[MAX], t[MAX]; __int64 cnt; void Merge(int l, int mid, int r) { int i = l, j = mid + 1, k = 0; while(i <= mid && j <= r) { if(a[i] > a[j]) { t[k++] = a[j++]; cnt += mid - i + 1; } else { t[k++] = a[i++]; } } while(i <= mid) t[k++] = a[i++]; while(j <= r) t[k++] = a[j++]; for(i = 0; i < k; i++) a[l+i] = t[i]; } void MergeSort(int l, int r) { int mid = (l + r) / 2; if(l < r) { MergeSort(l, mid); MergeSort(mid+1, r); Merge(l, mid, r); } } int main() { int n, i; while(scanf("%d", &n) != EOF && n) { for(i = 0; i < n; i++) scanf("%d", &a[i]); cnt = 0; MergeSort(0, n-1); printf("%I64d\n", cnt); } return 0; }
树状数组主要是这张图片:
inline int Lowbit(int x) { return x & (-x); } void Update(int x, int c) { int i; for (i = x; i < maxn; i += Lowbit(i)) { tree[i] += c; } } int Getsum(int x) { int i; int temp(0); for (i = x; i >= 1; i -= Lowbit(i)) { temp += tree[i]; } return temp; }以上三个函数可以说是树状数组的“看家本事”,树状数组的高效就体现在这三个函数上了。
Lowbit(x),是求出2^p(其中p为x的二进制表示中最右边的那个1的位置),如6的二进制表示为110,最右边的1为1,故Lowbit(6) = 2^1 = 2。
Update(x, c),是使x这点的值改变c,如果是一般数组改变的就是x自己这点,但是树状数组中要把(x, x+Lowbit(x), x+Lowbit(x+Lowbit(x))),…)这条路径的点都要改变c,这样做是为了后面能够高效地求和。(注意x的值可能是实际的值,也可能是数组的下标,如果太大的话需要离散化)
Getsum(x), 是求的(1, …x-Lowbit(x-Lowbit(x))), x-Lowbit(x), x)这条路径的点的和,换句话说就相当于求一般数组a[1]到a[x]的和。
树状数组的高效就在于: 与一般数组不同,一般数组都是下标不断加一来遍历的,而树状数组是不断加2^p来变化的,故效率为(logn)级别的。
树状数组的最基本功能就是求比某点x小的点的个数(这里的比较是抽象的概念,可以使数的大小,坐标的大小,质量的大小等)。
比如给定个数组a[5] = {2, 5, 3, 4, 1},求b[i] = 位置i左边小于等于a[i]的数的个数.如b[5] = {0, 1, 1, 2, 0},这是最正统的树状数组的应用,直接遍历遍数组,每个位置先求出Getsum(a[i]),然后再修改树状数组Update(a[i], 1)即可。当数的范围比较大时需要进行离散化,即先排个序,再重新编号。如a[] = {10000000, 10, 2000, 20, 300},那么离散化后a[] = {5, 1, 4, 2, 3}。(本题就是这个例子)
详细资料:http://download.csdn.net/detail/vsooda/4985249
#include <iostream> #include <algorithm> #define MAX 500010 using namespace std; typedef struct ARR{ int n,ind; }ARR; ARR a[MAX]; long long sum; int c[MAX],aa[MAX]; //c保存交换次数, aa保存离散化结果 bool cmp( ARR a, ARR b ) { return a.n > b.n; } int Lowbit(int x) { return x & (-x); } void Update(int x) { while( x < MAX ) { c[x]++; x += Lowbit(x); } } int Getsum(int x) { int sum = 0; while( x > 0 ) { sum += c[x]; x -= Lowbit(x); } return sum; } int main() { int n,i,tmp; while( ~scanf("%d",&n) && n ) { sum = 0ll; memset(c,0,sizeof(c)); for(i=1; i<=n; i++) { scanf("%d",&a[i].n); a[i].ind = i; //记住下标 } sort(a+1,a+n+1,cmp); int p = 1; aa[ a[1].ind ] = p; tmp = a[1].n; for(i=1; i<=n; i++) //离散化 { if( a[i].n == tmp ) aa[ a[i].ind ] = p; else { tmp = a[i].n; p++; aa[ a[i].ind ] = p; } } for(i=1; i<=n; i++) { sum += Getsum(aa[i]); Update(aa[i]); } printf("%lld\n",sum); } return 0; }
相关文章推荐
- POJ 2299 Ultra-QuickSort(树状数组入门) 求逆序数
- poj 2299 Ultra-QuickSort(树状数组求逆序数)
- POJ2299 Ultra-QuickSort(逆序数问题,树状数组求解)
- POJ 2299 Ultra-QuickSort【求逆序数:归并排序|树状数组】
- 树状数组求逆序数poj2299
- poj2299 树状数组快速求逆序数
- POJ 2299 Ultra-QuickSort 【归并排序 || 树状数组求逆序对数】
- Ultra-QuickSort poj 2299--树状数组求逆序数
- POJ 2299 Ultra-QuickSort 求逆序数 树状数组
- poj 2299 Ultra-QuickSort (树状数组求逆序数)
- 树状数组知识入门
- POJ2299 Ultra-QuickSort(树状数组求逆序数)
- POJ 2299 -Ultra-QuickSort-树状数组求逆序数
- POJ 2299 Ultra-QuickSort(树状数组求逆序数)
- 树状数组与逆序数——树状数组实践POJ3067
- poj 2299 Ultra-QuickSort 求逆序数 树状数组解法
- poj 2299树状数组求逆序数
- poj 2299 Ultra-QuickSort(树状数组求逆序数)
- POJ 2299 Ultra-QuickSort 【归并排序求逆序数 OR 树状数组求逆序数】
- poj 2299 Ultra-QuickSort 求逆序数 树状数组解法