初次接触CDQ分治,感觉真的挺厉害的。整体思路即分而治之,再用之前处理出来的答案统计之后的答案。

大概流程是(对于区间 l ~ r):

1.处理 l ~mid, mid + 1 ~ r 的答案;

2.分别排序规整;

3.计算 l ~ mid 中每一个数对 mid + 1 ~ r 中的答案的贡献, 累加;

4.得到区间l ~ r的答案。

CDQ分治我一共也才做了两道题目, 就一起整理在这里了。大体都差不多,CDQ+树状数组分别维护两个维度。

1.三维偏序

  1. #include <bits/stdc++.h>
  2. using namespace std;
  3. #define maxn 3000000
  4. #define lowbit(x) x &(-x)
  5. int n, k, tot, ans[maxn], c[maxn];
  6. struct node
  7. {
  8. int a, b, c, ans, cnt;
  9. }num[maxn], a[maxn];
  10.  
  11. int read()
  12. {
  13. int x = , k = ;
  14. char c;
  15. c = getchar();
  16. while(c < '' || c > '') { if(c == '-') k = -; c = getchar();}
  17. while(c >= '' && c <= '') x = x * + c - '', c = getchar();
  18. return x * k;
  19. }
  20.  
  21. bool cmp(node a, node b)
  22. {
  23. if(a.a != b.a) return a.a < b.a;
  24. if(a.b != b.b) return a.b < b.b;
  25. return a.c < b.c;
  26. }
  27.  
  28. bool cmp2(node a, node b)
  29. {
  30. if(a.b != b.b) return a.b < b.b;
  31. return a.c < b.c;
  32. }
  33.  
  34. void Update(int x, int v)
  35. {
  36. for(int i = x; i <= k; i += lowbit(i))
  37. c[i] += v;
  38. }
  39.  
  40. int Query(int x)
  41. {
  42. int ans = ;
  43. for(int i = x; i; i -= lowbit(i))
  44. ans += c[i];
  45. return ans;
  46. }
  47.  
  48. void cdq(int l, int r)
  49. {
  50. int mid = (l + r) >> ;
  51. if(r - l >= ) cdq(l, mid), cdq(mid + , r);
  52. if(r == l) return;
  53. sort(num + l, num + mid + , cmp2);
  54. sort(num + mid + , num + r + , cmp2);
  55. int i = l, j = mid + ;
  56. while(i <= mid && j <= r)
  57. {
  58. if(num[i].b <= num[j].b) Update(num[i].c, num[i].cnt), i ++;
  59. else num[j].ans += Query(num[j].c), j ++;
  60. }
  61. while(i <= mid) Update(num[i].c, num[i].cnt), i ++;
  62. while(j <= r) num[j].ans += Query(num[j].c), j ++;
  63. for(int i = l; i <= mid; i ++) Update(num[i].c, -num[i].cnt);
  64. }
  65.  
  66. int main()
  67. {
  68. n = read(), k = read();
  69. for(int i = ; i <= n; i ++)
  70. a[i].a = read(), a[i].b = read(), a[i].c = read();
  71. sort(a + , a + + n, cmp);
  72. for(int i = ; i <= n;)
  73. {
  74. int j = ;
  75. while(i + j <= n && a[i].a == a[i + j].a && a[i].b == a[i + j].b && a[i].c == a[i + j].c) j ++;
  76. num[++ tot] = a[i];
  77. num[tot].cnt = j;
  78. i += j;
  79. }
  80. cdq(, tot);
  81. for(int i = ; i <= tot; i ++) ans[num[i].ans + num[i].cnt - ] += num[i].cnt;
  82. for(int i = ; i < n; i ++) printf("%d\n", ans[i]);
  83. return ;
  84. }

2.动态逆序对

  1. #include <bits/stdc++.h>
  2. using namespace std;
  3. #define maxn 2000000
  4. #define ll long long
  5. #define lowbit(x) x & (-x)
  6. int n, m, timer, a[maxn], b[maxn], d[maxn], t[maxn];
  7. ll ans[maxn], c[maxn];
  8. struct node
  9. {
  10. int t, num, pl;
  11. ll ans;
  12. }w[maxn];
  13.  
  14. int read()
  15. {
  16. int x = , k = ;
  17. char c;
  18. c = getchar();
  19. while(c < '' || c > '') { if(c == '-') k = -; c = getchar();}
  20. while(c >= '' && c <= '') x = x * + c - '', c = getchar();
  21. return x * k;
  22. }
  23.  
  24. bool cmp(node a, node b)
  25. {
  26. if(a.t != b.t) return a.t < b.t;
  27. else return a.pl < b.pl;
  28. }
  29.  
  30. bool cmp2(node a, node b)
  31. {
  32. return a.pl < b.pl;
  33. }
  34.  
  35. bool cmp3(node a, node b)
  36. {
  37. return a.pl > b.pl;
  38. }
  39.  
  40. void add(int x, int num)
  41. {
  42. for(int i = x; i <= n; i += lowbit(i))
  43. c[i] += num;
  44. }
  45.  
  46. ll query(int x)
  47. {
  48. ll ans = ;
  49. for(int i = x; i; i -= lowbit(i))
  50. ans += c[i];
  51. return ans;
  52. }
  53.  
  54. void CDQ(int l, int r)//位置在我之前,num>我的
  55. {
  56. int mid = (l + r) >> ;
  57. if(r - l >= ) CDQ(l, mid), CDQ(mid + , r);
  58. if(l == r) return;
  59. sort(w + l, w + + mid, cmp2);
  60. sort(w + mid + , w + r + , cmp2);
  61. int i = l, j = mid + ;
  62. while(i <= mid && j <= r)
  63. {
  64. if(w[i].pl < w[j].pl) add(w[i].num, ), i ++;
  65. else w[j].ans += (query(n) - query(w[j].num)), j ++;
  66. }
  67. while(i <= mid) add(w[i].num, ), i ++;
  68. while(j <= r) w[j].ans += (query(n) - query(w[j].num)), j ++;
  69. for(int i = l; i <= mid; i ++)
  70. add(w[i].num, -);
  71. }
  72.  
  73. void CDQ2(int l, int r)//位置在我之后,num<我的
  74. {
  75. int mid = (l + r) >> ;
  76. if(r - l >= ) CDQ2(l, mid), CDQ2(mid + , r);
  77. if(l == r) return;
  78. sort(w + l, w + + mid, cmp3);
  79. sort(w + mid + , w + r + , cmp3);
  80. int i = l, j = mid + ;
  81. while(i <= mid && j <= r)
  82. {
  83. if(w[i].pl > w[j].pl) add(w[i].num, ), i ++;
  84. else w[j].ans += (query(w[j].num)), j ++;
  85. }
  86. while(i <= mid) add(w[i].num, ), i ++;
  87. while(j <= r) w[j].ans += (query(w[j].num)), j ++;
  88. for(int i = l; i <= mid; i ++)
  89. add(w[i].num, -);
  90. }
  91.  
  92. int main()
  93. {
  94. n = read(), m = read();
  95. for(int i = ; i <= n; i ++)
  96. {
  97. a[i] = read();
  98. b[a[i]] = i;
  99. }
  100. timer = m;
  101. for(int i = ; i <= m; i ++)
  102. {
  103. d[i] = read();
  104. t[b[d[i]]] = timer --;
  105. }
  106. for(int i = ; i <= n; i ++) w[i].t = t[i], w[i].num = a[i], w[i].pl = i;
  107. sort(w + , w + + n, cmp);
  108. CDQ(, n);
  109. for(int i = ; i <= n; i ++) ans[w[i].t] += w[i].ans;
  110. for(int i = ; i <= n; i ++) w[i].t = t[i], w[i].num = a[i], w[i].pl = i, w[i].ans = ;
  111. sort(w + , w + + n, cmp);
  112. memset(c, , sizeof(c));
  113. CDQ2(, n);
  114. for(int i = ; i <= n; i ++) ans[w[i].t] += w[i].ans;
  115. for(int i = ; i <= m; i ++) ans[i] += ans[i - ];
  116. for(int i = m; i >= ; i --) printf("%lld\n", ans[i]);
  117. return ;
  118. }

【算法】CDQ分治 -- 三维偏序 & 动态逆序对的更多相关文章

  1. cdq分治·三维偏序问题

    转载自FlashHu大佬的博客CDQ分治总结(CDQ,树状数组,归并排序),在讲述部分有部分删改,用了自己的代码 CDQ分治的思想 CDQ分治是基于时间的离线分治算法.这一类分治有一个重要的思想——用 ...

  2. BZOJ 3262: 陌上花开 [CDQ分治 三维偏序]

    Description 有n朵花,每朵花有三个属性:花形(s).颜色(c).气味(m),又三个整数表示.现要对每朵花评级,一朵花的级别是它拥有的美丽能超过的花的数量.定义一朵花A比另一朵花B要美丽,当 ...

  3. 洛谷P3810 陌上花开 CDQ分治(三维偏序)

    好,这是一道三维偏序的模板题 当然没那么简单..... 首先谴责洛谷一下:可怜的陌上花开的题面被无情的消灭了: 这么好听的名字#(滑稽) 那么我们看了题面后就发现:这就是一个三维偏序.只不过ans不加 ...

  4. NEUOJ 1702:撩妹全靠魅力值(CDQ分治三维偏序)

    http://acm.neu.edu.cn/hustoj/problem.php?id=1702 思路:三维偏序模板题,用CDQ分治+树状数组或者树套树.对于三元组(x,y,z),先对x进行排序,然后 ...

  5. BZOJ 2244: [SDOI2011]拦截导弹 (CDQ分治 三维偏序 DP)

    题意 略- 分析 就是求最长不上升子序列,坐标取一下反就是求最长不下降子序列,比较大小是二维(h,v)(h,v)(h,v)的比较.我们不看概率,先看第一问怎么求最长不降子序列.设f[i]f[i]f[i ...

  6. CDQ分治 三维偏序

    这应该是一道CDQ分治的入门题目 我们知道,二维度的偏序问题直接通过,树状数组就可以实现了,但是三维如何实现呢? 我记得以前了解过一个小故事,应该就是分治的. 一个皇帝,想给部下分配任务,但是部下太多 ...

  7. BZOJ.1935.[SHOI2007]Tree园丁的烦恼(CDQ分治 三维偏序)

    题目链接 矩形查询可以拆成四个点的前缀和查询(树套树显然 但是空间不够) 每个操作表示为(t,x,y),t默认有序,对x分治,y用树状数组维护 初始赋值需要靠修改操作实现. //119964kb 43 ...

  8. BZOJ.3262.陌上花开([模板]CDQ分治 三维偏序)

    题目链接 BZOJ3262 洛谷P3810 /* 5904kb 872ms 对于相邻x,y,z相同的元素要进行去重,并记录次数算入贡献(它们之间产生的答案是一样的,但不去重会..) */ #inclu ...

  9. BZOJ - 1935 / 1176 cdq分治 三维偏序

    题意:给定n*m的网格,且给出n个(x,y)表示该网格已被占有,q次询问(x1,y1)到(x2,y2)的网格中有多少个被占有,n,m范围1e7,q范围5e5 cdq按x轴排序,树状数组维护y轴 #in ...

随机推荐

  1. jQuery获取data-*属性值

    下面就详细介绍四种方法获取data-*属性的值 <li id="getId" data-id="122" data-vice-id="11&qu ...

  2. springcloud生态图

    springcloud生态图

  3. Hadoop(13)-MapReduce框架原理--Job提交源码和切片源码解析

    1.MapReduce的数据流 1) Input -> Mapper阶段 这一阶段的主要分工就是将文件切片和把文件转成K,V对 输入源是一个文件,经过InputFormat之后,到了Mapper ...

  4. Node.js中的不安全跳转如何防御详解

    Node.js中的不安全跳转如何防御详解 导语: 早年在浏览器大战期间,有远见的Chrome认为要运行现代Web应用,浏览器必须有一个性能非常强劲的Java引擎,于是Google自己开发了一个高性能的 ...

  5. vue---day04

    1. Node.js 1.1 介绍: - Node.js 是一个JavaScript运行环境,实质上是对Chrome V8引擎的封装. - Node.js 不是一个 JavaScript 框架,不同于 ...

  6. Educational Codeforces Round 47 (Rated for Div. 2) :B. Minimum Ternary String

    题目链接:http://codeforces.com/contest/1009/problem/B 解题心得: 题意就是给你一个只包含012三个字符的字符串,位置并且逻辑相邻的字符可以相互交换位置,就 ...

  7. [Cracking the Coding Interview] 4.3 List of Depths

    Given a binary tree, design an algorithm which creates a linked list of all the nodes at each depth. ...

  8. SapScript

    * [OPEN_FORM] SAPscript: フォーム印刷の開始 * [START_FORM] SAPscript: 書式を開始 * [WRITE_FORM] SAPscript: 書式ウィンドウ ...

  9. 教你如何更改xshell中的转发规则

    使用不同的类型转发,与之对应的端口,所以如果想要使用不同类型的转发就要更改端口使其与之一一对应.本集xshell专栏文章将为大家讲解如何更改转发规则. 更改转发规则操作如下: 1.打开会话对话框. 2 ...

  10. 关于springboot 打包问题 jar包和 war包

    起因:项目开发完成   需要打包部署了  发现自己不会打包 那么开始网上学习打包? 那么怎么来打包那? 我们以前没有采用springboot 时候我们都是直接将项目打成war包形式  然后放到tomc ...