树状数组求逆序对与luogu1908

  

  今天上午,我完成了树状数组求逆序对[1]的学习,并完成了luogu1908的编程与调试,以下是一些记录与感想:

 

  树状数组求逆序对的中心思想是:

    1、树状数组c[a[i]]记录a[i]出现的次数,然后利用树状数组求小于a[i]的数的个数s[i][2]

    2、用i - s[i]表示输入到当前时,大于a[i]的数的个数(即关于a[i]的逆序对的个数)。

 

  以下是我的代码:

 1 //由于我们可以把s[i]直接累加到ans中,故不需要开s数组
 2 //<&x>为跳转符
 3 //以下是未离散化代码
 4 //以下是C++代码
 5 
 6 #include<cstdio>
 7 
 8 int a[40006];
 9 //由于题目没有说明a[i]的最大值(只说是正整数),故将c数组范围往大的开
10 //max为a[i]最大值
11 int c[5000000] = {0}, n, ans(0), max(0);
12 
13 void add_c(int x);                           //更新c数组
14 int sum(int x);                              //求小于a[i]的数的个数
15 int lowbit(const int &x);
16 
17 int main() 
18 {
19     scanf("%d", &n);
20     for(int i = 1; i <= n; ++i)
21     {
22         scanf("%d", &a[i]); 
23                 max = max < a[i] ? a[i] : max;
24     }
25         //与以往代码不同,本次我将处理放在读入的循环之后
26         //这是因为a[i]的范围不确定,在<&x>处循环到5000000太耗时间
27     for(int i = 1; i <= n; ++i)
28     {
29         add_c(a[i]);
30         ans += i - sum(a[i]);
31     }
32     printf("%d\n", ans);
33 }
34 
35 void add_c(int x)
36 {
37     while (x <= max)                         //<&x>
38     {
39         ++c[x];
40         x += lowbit(x);
41     }
42 }
43 
44 int sum(int x)
45 {
46     int s(0);
47     while (x > 0)
48     {
49         s += c[x];
50         x -= lowbit(x);
51     }
52     return s;
53 }
54 
55 int lowbit(const int &x)
56 {
57     return x & (-x);
58 }

 

  根据注释[1]链接的内容,我又做了一份离散化版本。但尴尬的的是,对这题来说,离散化后代码又长速度又慢……(所用时间是未离散化的两倍,不过能过就是了……)

 

 1 //以下是加入离散化的代码,离散化部分从<&beg>到<&end>,其余部分有较小规模改动
 2 //以下是C++代码
 3 
 4 #include<cstdio>
 5 #include<algorithm>
 6 
 7 struct map__
 8 {
 9     int in, to, po;                   //in:a[i]值;to:离散化目标值;po:输入顺序
10 }a[40006];
11 int c[5000000] = {0}, n, ans(0), p(0);//p:离散化目标最大值(max(to))
12 
13 //cmp1与cmp2分别用于in与po的sort排序
14 inline bool cmp1(const map__ &a, const map__ &b);
15 inline bool cmp2(const map__ &a, const map__ &b);
16 void add_c(int x);
17 int sum(int x);
18 int lowbit(const int &x);
19 
20 int main() 
21 {
22     scanf("%d", &n);
23     for(int i = 1; i <= n; ++i)
24     {
25         scanf("%d", &a[i].in);
26         a[i].po = i;
27     }
28     //<&beg>
29     std::sort(a + 1, a + n + 1, cmp1);
30     for(int i = 1; i <= n; ++i)
31     {
32         if(a[i].in == a[i - 1].in) a[i].to = a[i - 1].to;
33         else a[i].to = ++p;
34     }
35     std::sort(a + 1, a + n + 1, cmp2);
36     //<&end>
37     for(int i = 1; i <= n; ++i)
38     {
39         add_c(a[i].to);
40         ans += i - sum(a[i].to);
41     }
42     printf("%d\n", ans);
43 }
44 
45 inline bool cmp1(const map__ &a, const map__ &b)
46 {
47     return a.in < b.in;
48 }
49 
50 inline bool cmp2(const map__ &a, const map__ &b)
51 {
52     return a.po < b.po;
53 }
54 
55 void add_c(int x)
56 {
57     while (x <= p)
58     {
59         ++c[x];
60         x += lowbit(x);
61     }
62 }
63 
64 int sum(int x)
65 {
66     int s(0);
67     while (x > 0)
68     {
69         s += c[x];
70         x -= lowbit(x);
71     }
72     return s;
73 }
74 
75 int lowbit(const int &x)
76 {
77     return x & (-x);
78 }

 

  注意:由于本人也是第一次接触离散化,而且只是尝试按照自己理解编,所以离散化部分应该可以大幅优化,欢迎看到这篇文章的dalao指点一二。

  感想:个人感觉,其实只要把问题转化为“求从开始输入到当前,比当前这个数更大的数的个数,最后将结果累加”之后,剩下的编程实现就异常简单了(当然,前提是学会使用树状数组)。

 

  注释:

    [1]:树状数组求逆序对:http://www.360doc.com/content/12/0925/21/9615799_238155264.shtml

    [2]:关于树状数组的基础内容,请参看本人之前的的两篇文章及如下链接:http://www.cnblogs.com/justforgl/archive/2012/07/27/2612364.html

 

 

  (转载请注明出处)

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值