给定空间中的n个点,问每个点有多少个点小于等于自己。

先来分析简单的二维的情况,那么只要将x坐标排序,那么这样的问题就可以划分为两个子问题,,这样的分治有一个特点,即前一个子问题的解决是独立的,而后一个子问题的解决依赖于前一个子问题,即用前一个子问题来解决后一个子问题,而不是合并。 这就是cdq分治。

具体的代码如下。

  1. void cdq(int l, int r){
  2. if(l==r) return;
  3. int m = (l+r)>>;
  4. cdq(l,m);
  5. cdq(m+,r);
  6. //按y进行排序,那么问题就变成两个y递增的集合,
  7. //后一个集合中的每个y在前一个集合中有多少个y小于等于它
  8. sort(a+l,a+m+,cmp);
  9. sort(a+m+,a+r+,cmp);
  10. int j = l;
  11. for(int i=m+;i<=r;++i){
  12. for(;j<=m;&&a[j].y<=a[i].y;++j);
  13. a[i].sum += j - l;
  14. }
  15. }

而三维的问题由于多了一维,不能使用线性的方法 了。

我们可以用树状数组来维护z这一维,具体的代码如下。

并且最后要注意坐标相等的情况。

第一份代码,因为cdq里面又嵌套了sort,所以时间复杂度是O(n*logn*logn)

  1. #include <stdio.h>
  2. #include <math.h>
  3. #include <algorithm>
  4. #include <iostream>
  5. #include <string.h>
  6. using namespace std;
  7. struct Point{
  8. int x,y,z;
  9. int id;
  10. int sum;
  11. Point(){}
  12. Point(int x, int y):x(x),y(y){}
  13. bool operator<(const Point&rhs)const{
  14. if(x!=rhs.x) return x < rhs.x;
  15. if(y!=rhs.y) return y < rhs.y;
  16. return z < rhs.z;
  17. }
  18. bool operator==(const Point &rhs)const{
  19. return x==rhs.x && y==rhs.y && z==rhs.z;
  20. }
  21. };
  22. bool cmp(const Point &lhs, const Point &rhs){
  23. if(lhs.y!=rhs.y) return lhs.y <rhs.y;
  24. return lhs.z <rhs.z;
  25. }
  26. const int N = + ;
  27. Point a[N];
  28. class BIT{
  29. public:
  30. int sum[N];
  31. int n;
  32. void init(){
  33. n = ;
  34. memset(sum,,sizeof(sum));
  35. }
  36. int lowbit(int x){
  37. return x & (-x);
  38. }
  39. int modify(int x, int val){
  40. while(x<=n){
  41. sum[x] += val;
  42. x += lowbit(x);
  43. }
  44. }
  45. int getSum(int x){
  46. int ret= ;
  47. while(x>){
  48. ret += sum[x];
  49. x -= lowbit(x);
  50. }
  51. return ret;
  52. }
  53. }bit;
  54.  
  55. void cdq(int l, int r){
  56. if(l==r)return;
  57. int m = (l+r)>>;
  58. cdq(l,m);
  59. cdq(m+,r);
  60. sort(a+l,a+m+,cmp);
  61. sort(a+m+,a+r+,cmp);
  62. int j = l;
  63. for(int i=m+;i<=r;++i){
  64. for(;j<=m &&a[j].y<=a[i].y;++j)
  65. bit.modify(a[j].z,);
  66. a[i].sum += bit.getSum(a[i].z);
  67. }
  68. for(int i=l; i<j; ++i)
  69. bit.modify(a[i].z,-);
  70.  
  71. }
  72.  
  73. int ans[N];
  74. int main(){
  75. int t,n;
  76. scanf("%d",&t);
  77. while(t--){
  78.  
  79. scanf("%d",&n);
  80. for(int i=;i<n;++i){ scanf("%d%d%d",&a[i].x,&a[i].y,&a[i].z); a[i].id = i; a[i].sum=;}
  81. sort(a,a+n);
  82. bit.init();
  83. cdq(,n-);
  84. sort(a,a+n);
  85. for(int i=;i<n;){
  86. int j = i + ;
  87. int tmp = a[i].sum;
  88. //分治时,坐标相等的时候,
  89. //排在前边的坐标不能使用后边的坐标更新自己,所以要在这里处理一下
  90. for(;j<n &&a[i]==a[j];++j) tmp = max(tmp,a[j].sum);
  91. for(int k=i;k<j;++k) ans[a[k].id] = tmp;
  92.  
  93. i = j;
  94. }
  95. for(int i=;i<n;++i)
  96. printf("%d\n",ans[i]);
  97. }
  98. return ;
  99. }

第二份代码,在cdq分治的最后加入归并排序,是的复杂度变成O(n*logn)

  1. #include <stdio.h>
  2. #include <math.h>
  3. #include <algorithm>
  4. #include <iostream>
  5. #include <string.h>
  6. using namespace std;
  7. struct Point{
  8. int x,y,z;
  9. int id;
  10. int sum;
  11. Point(){}
  12. Point(int x, int y):x(x),y(y){}
  13. bool operator<(const Point&rhs)const{
  14. if(x!=rhs.x) return x < rhs.x;
  15. if(y!=rhs.y) return y < rhs.y;
  16. return z < rhs.z;
  17. }
  18. bool operator==(const Point &rhs)const{
  19. return x==rhs.x && y==rhs.y && z==rhs.z;
  20. }
  21. };
  22. bool cmp(const Point &lhs, const Point &rhs){
  23. if(lhs.y!=rhs.y) return lhs.y <rhs.y;
  24. return lhs.z <rhs.z;
  25. }
  26. const int N = + ;
  27. Point a[N];
  28. class BIT{
  29. public:
  30. int sum[N];
  31. int n;
  32. void init(){
  33. n = ;
  34. memset(sum,,sizeof(sum));
  35. }
  36. int lowbit(int x){
  37. return x & (-x);
  38. }
  39. int modify(int x, int val){
  40. while(x<=n){
  41. sum[x] += val;
  42. x += lowbit(x);
  43. }
  44. }
  45. int getSum(int x){
  46. int ret= ;
  47. while(x>){
  48. ret += sum[x];
  49. x -= lowbit(x);
  50. }
  51. return ret;
  52. }
  53. }bit;
  54.  
  55. Point tmp[N];
  56. void cdq(int l, int r){
  57. if(l==r)return;
  58. int m = (l+r)>>;
  59. cdq(l,m);
  60. cdq(m+,r);
  61. //sort(a+l,a+m+1,cmp);
  62. //sort(a+m+1,a+r+1,cmp);
  63. int j = l;
  64. for(int i=m+;i<=r;++i){
  65. for(;j<=m &&a[j].y<=a[i].y;++j)
  66. bit.modify(a[j].z,);
  67. a[i].sum += bit.getSum(a[i].z);
  68. }
  69. for(int i=l; i<j; ++i)
  70. bit.modify(a[i].z,-);
  71.  
  72. //归并排序, 这样就不需要上面的sort了
  73. int i = l ;
  74. j = m+;
  75. for(int k=l;k<=r;++k){
  76. if(i>m) tmp[k] = a[j++];
  77. else if(j>r) tmp[k] = a[i++];
  78. else if(a[i].y < a[j].y) tmp[k] = a[i++];
  79. else tmp[k] = a[j++];
  80. }
  81. for(int k=l;k<=r;++k)
  82. a[k] = tmp[k];
  83.  
  84. }
  85.  
  86. int ans[N];
  87. int main(){
  88. int t,n;
  89. scanf("%d",&t);
  90. while(t--){
  91.  
  92. scanf("%d",&n);
  93. for(int i=;i<n;++i){ scanf("%d%d%d",&a[i].x,&a[i].y,&a[i].z); a[i].id = i; a[i].sum=;}
  94. sort(a,a+n);
  95. bit.init();
  96. cdq(,n-);
  97. sort(a,a+n);
  98. for(int i=;i<n;){
  99. int j = i + ;
  100. int tmp = a[i].sum;
  101. //分治时,坐标相等的时候,
  102. //排在前边的坐标不能使用后边的坐标更新自己,所以要在这里处理一下
  103. for(;j<n &&a[i]==a[j];++j) tmp = max(tmp,a[j].sum);
  104. for(int k=i;k<j;++k) ans[a[k].id] = tmp;
  105.  
  106. i = j;
  107. }
  108. for(int i=;i<n;++i)
  109. printf("%d\n",ans[i]);
  110. }
  111. return ;
  112. }

具体算法流程如下:

1.将整个操作序列分为两个长度相等的部分(分)

2.递归处理前一部分的子问题(治1)

3.计算前一部分的子问题中的修改操作对后一部分子问题的影响(治2)

4.递归处理后一部分子问题(治3)

而且如果需要分治完后数据要求有序,那么就可以在分治的最后加入归并排序等手段。

何时使用cdq分治:①如果一个问题的解决需要去循环判断,且这样的问题有很多, 那么就看看能不能分治,减少计算量,从小减小复杂度。

hdu5618 (三维偏序,cdq分治)的更多相关文章

  1. Luogu 3810 & BZOJ 3262 陌上花开/三维偏序 | CDQ分治

    Luogu 3810 & BZOJ 3263 陌上花开/三维偏序 | CDQ分治 题面 \(n\)个元素,每个元素有三个值:\(a_i\), \(b_i\) 和 \(c_i\).定义一个元素的 ...

  2. bzoj3262: 陌上花开 三维偏序cdq分治

    三维偏序裸题,cdq分治时,左侧的x一定比右侧x小,然后分别按y排序,对于左侧元素按y大小把z依次插入到树状数组里,其中维护每个左侧元素对右侧元素的贡献,在bit查询即可 /************* ...

  3. [bzoj] 3263 陌上花开 洛谷 P3810 三维偏序|| CDQ分治 && CDQ分治讲解

    原题 定义一个点比另一个点大为当且仅当这个点的三个值分别大于等于另一个点的三个值.每比一个点大就为加一等级,求每个等级的点的数量. 显然的三维偏序问题,CDQ的板子题. CDQ分治: CDQ分治是一种 ...

  4. BZOJ3262 陌上花开 —— 三维偏序 CDQ分治

    题目链接:https://vjudge.net/problem/HYSBZ-3262 3262: 陌上花开 Time Limit: 20 Sec  Memory Limit: 256 MBSubmit ...

  5. BZOJ 3295:[Cqoi2011]动态逆序对(三维偏序 CDQ分治+树状数组)

    http://www.lydsy.com/JudgeOnline/problem.php?id=3295 题意:简单明了. 思路:终于好像有点明白CDQ分治处理三维偏序了.把删除操作看作是插入操作,那 ...

  6. 三维偏序[cdq分治学习笔记]

    三维偏序 就是让第一维有序 然后归并+树状数组求两维 cdq+cdq不会 告辞 #include <bits/stdc++.h> // #define int long long #def ...

  7. 洛谷P3810-陌上开花(三维偏序, CDQ, 树状数组)

    链接: https://www.luogu.org/problem/P3810#submit 题意: 一个元素三个属性, x, y, z, 给定求f(b) = {ax <= bx, ay < ...

  8. COGS 2479. [HZOI 2016]偏序 [CDQ分治套CDQ分治 四维偏序]

    传送门 给定一个有n个元素的序列,元素编号为1~n,每个元素有三个属性a,b,c,求序列中满足i<j且ai<aj且bi<bj且ci<cj的数对(i,j)的个数. 对于100%的 ...

  9. BZOJ 2716/2648 SJY摆棋子 (三维偏序CDQ+树状数组)

    题目大意: 洛谷传送门 这明明是一道KD-Tree,CDQ分治是TLE的做法 化简式子,$|x1-x2|-|y1-y2|=(x1+y1)-(x2+y2)$ 而$CDQ$分治只能解决$x1 \leq x ...

随机推荐

  1. 发掘ListBox的潜力(三):显示即时提示(Tips)

    ListBox显示即时提示(Tips) Listbox内容太长时超出Listbox宽度的部分将无法显示,一种解决方法是让Listbox产生横向滚动条,滚动显示内容(见前面的<发掘ListBox的 ...

  2. 在程序异常中记录堆栈信息(使用ExWatcher)

    在我们编写程序的时候可通过IDE自带的调试环境捕捉到异常(Except)错误,并能查看到相关的信息以便我们修正程序中的问题.但当软件被发布出去后,因为所部署运行的环境与我们的调试环境有很大区别,即使在 ...

  3. Minor GC、Major GC和Full GC之间的区别(转)

    在 Plumbr 从事 GC 暂停检测相关功能的工作时,我被迫用自己的方式,通过大量文章.书籍和演讲来介绍我所做的工作.在整个过程中,经常对 Minor.Major.和 Full GC 事件的使用感到 ...

  4. 【Unity 3D】学习笔记三十九:控制组件

    控制组件 角色控制组件和刚体组件都具备物理引擎的功能,须要绑定游戏对象才干实现对应的物理效果,而且同一个游戏对象中两者仅仅能存在一个,不能共存.刚体组件能够很精确的模拟现实世界中的一切物理效果,而角色 ...

  5. VC 实现视图区背景颜色渐变填充

    void CSTest1View::OnDraw(CDC* pDC) { CSTest1Doc* pDoc = GetDocument(); ASSERT_VALID(pDoc); // TODO:  ...

  6. java.text.MessageFormat格式化字符串时的小技巧

    java.text.MessageFormat格式化字符串时的小技巧 public static void main(String[] args) throws InterruptedExceptio ...

  7. gap锁 对于unique index 和Ununique index

    Session 1: mysql> select * from s100; +-----+------+------+ | sn | id | info | +-----+------+---- ...

  8. c++ 类名和enum时重复时要在类名前加class::

    c++ 类名和enum时重复时要在类名前加class:: 一些不好的习惯都是用小写,但又没有区分开token,看看代码再说,下面的代码是我在测试polymorphism时写的一部分,怎么也查不出,最后 ...

  9. Eclipse代码字体、颜色美化,更改字体大小、颜色

    先看效果: 感觉如何,是否比你的eclipse编辑器显示的代码要漂亮简洁呢?呵呵.这个是我原来ADT Eclipse的效果,现在去下居然更新掉了,找不到了.于是我就参照我原来的配置对这个新的Eclip ...

  10. Android代码混淆和项目宣布步骤记录器

    原本放在一起Android项目与发布的文件相混淆.我突然想到,为什么不写博客,分享.有这篇文章的情况下,. Android代码混淆及项目公布步骤记录 一.清理代码中的调试信息,如Log.System. ...