poj 2299 树状数组(离散化)求逆序数

Ultra-QuickSort


题目链接:点击打开链接

传送门:转载处

给定n个数,要求这些数构成的逆序对的个数。除了用归并排序来求逆序对个数,还可以使用树状数组来求解。

树状数组求解的思路:开一个能大小为这些数的最大值的树状数组,并全部置0。从头到尾读入这些数,每读入一个数就更新树状数组,查看它前面比它小的已出现过的有多少个数sum,然后用当前位置减去该sum,就可以得到当前数导致的逆序对数了。把所有的加起来就是总的逆序对数。

题目中的数都是独一无二的,这些数最大值不超过999999999,但n最大只是500000。如果采用上面的思想,必然会导致空间的巨大浪费,而且由于内存的限制,我们也不可能开辟这么大的数组。因此可以采用一种称为“离散化”的方式,把原始的数映射为1-n一共n个数,这样就只需要500000个int类型的空间。

离散化的方式:

struct Node

{

int val;

int pos;

};

Node node[500005];

int reflect[500005];

val存放原数组的元素,pos存放原始位置,即node[i].pos = i。

把这些结构体按照val的大小排序。

reflect数组存放离散化后的值,即reflect[node[i].pos] = i。

这样从头到尾读入reflect数组中的元素,即可以保持原来的大小关系,又可以节省大部分空间。

[cpp]  view plain  copy
  1. #include <iostream>  
  2. #include <cstring>  
  3. #include <cstdio>  
  4. #include <algorithm>  
  5. using namespace std;  
  6.   
  7. const int N = 500005;  
  8.   
  9. struct Node  
  10. {  
  11.     int val;  
  12.     int pos;  
  13. };  
  14.   
  15. Node node[N];  
  16. int c[N], reflect[N], n;  
  17.   
  18. bool cmp(const Node& a, const Node& b)  
  19. {  
  20.     return a.val < b.val;  
  21. }  
  22.   
  23. int lowbit(int x)  
  24. {  
  25.     return x & (-x);  
  26. }  
  27.   
  28. void update(int x)  
  29. {  
  30.     while (x <= n)  
  31.     {  
  32.         c[x] += 1;  
  33.         x += lowbit(x);  
  34.     }  
  35. }  
  36.   
  37. int getsum(int x)  
  38. {  
  39.     int sum = 0;  
  40.     while (x > 0)  
  41.     {  
  42.         sum += c[x];  
  43.         x -= lowbit(x);  
  44.     }  
  45.     return sum;  
  46. }  
  47.   
  48. int main()  
  49. {  
  50.     while (scanf("%d", &n) != EOF && n)  
  51.     {  
  52.         for (int i = 1; i <= n; ++i)   
  53.         {  
  54.             scanf("%d", &node[i].val);  
  55.             node[i].pos = i;  
  56.         }  
  57.         sort(node + 1, node + n + 1, cmp);   //排序  
  58.         for (int i = 1; i <= n; ++i) reflect[node[i].pos] = i;   //离散化  
  59.         for (int i = 1; i <= n; ++i) c[i] = 0;   //初始化树状数组  
  60.         long long ans = 0;  
  61.         for (int i = 1; i <= n; ++i)  
  62.         {  
  63.             update(reflect[i]);  
  64.             ans += i - getsum(reflect[i]);  
  65.         }  
  66.         printf("%lld\n", ans);  
  67.     }   
  68.     return 0;  
  69. }  


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值