树状数组求逆序对与luogu1908
来源:互联网 发布:源明雅捏脸数据 编辑:程序博客网 时间:2024/05/16 07:26
今天上午,我完成了树状数组求逆序对[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
- 树状数组求逆序对与luogu1908
- 树状数组求逆序对与luogu1908
- 树状数组求逆序对与luogu1908
- 树状数组求逆序对与luogu1908
- 树状数组求逆序对
- 树状数组求逆序对
- 树状数组求逆序对
- 树状数组求逆序对
- 树状数组求逆序对
- 树状数组求逆序对
- 树状数组求逆序对
- 树状数组求逆序对
- 树状数组求逆序对
- 树状数组求逆序对
- 树状数组求逆序对
- 树状数组求逆序对
- 树状数组求逆序对
- 树状数组求逆序对
- MTK battery 原理
- Open vSwitch的ovs-vsctl命令详解
- [LeetCode] Longest Substring Without Repeating Characters
- [Leetcode] #42 Trapping Rain Water
- 每日小记 2017.2.14
- 树状数组求逆序对与luogu1908
- 5.3客户端开发
- 如何解决数据库查询慢问题
- 10. 常见设计模式
- Android_闹钟AlarmManager的使用
- Redis性能问题排查解决手册(七)
- The Dole Queue UVA - 133
- 并查集详解
- 11. JDK 新特性