一:基本原理

image.png
初始化堆的时候,如果按照插入的原理,时间复杂度是nlogn,但是通过
for (int i = n / 2; i; i—) down(i)的方式,可以把时间复杂度降到O(n)的级别,分析方法如下,从n/2 往下,最小层是0,因此倒数第二层是第二层,往下操作就是n/4
1,也就是下图的计算,算出时间复杂度会小于n。
image.png

  1. #include <iostream>
  2. #include <algorithm>
  3. using namespace std;
  4. const int N = 1e5 + 10;
  5. int h[N];
  6. int si;
  7. int n, m;
  8. void down(int u) {
  9. int t = u;
  10. if (u * 2 <= si && h[u * 2] < h[u]) t = u * 2;
  11. if (u * 2 + 1 <= si && h[u * 2 + 1] < h[t]) t = u * 2 + 1;
  12. if (u != t) {
  13. swap(h[u], h[t]);
  14. down(t);
  15. }
  16. }
  17. //补充
  18. void up(int u) {
  19. while (u / 2 && h[u / 2] > h[u]) {
  20. swap(h[u / 2], h[u]);
  21. u = u / 2;
  22. }
  23. }
  24. int main() {
  25. ios::sync_with_stdio(false);
  26. cin >> n >> m;
  27. for (int i = 1; i <= n; i++)
  28. cin >> h[i];
  29. si = n;
  30. for (int i = n / 2; i; i--) down(i);
  31. while (m--) {
  32. cout << h[1] << " ";
  33. h[1] = h[si--];
  34. down(1);
  35. }
  36. return 0;
  37. }

二:堆的全部操作

一般的堆的情况下就是前面的down和up操作就可以了,但是Dijkistra算法是需要用到这种复杂的方式的。
image.png
第五个操作修改第k个插入的数字,就需要维护两个数,用两个数组维护第k个插入的数的位置。

  • ph[k] = i,第k个点的下标是i
  • hp[i] = k,下标为i的点是第k个点。

image.png

  1. #include <iostream>
  2. #include <string.h>
  3. #include <algorithm>
  4. using namespace std;
  5. const int N = 1e5 + 10;
  6. int n, m;
  7. int h[N], ph[N], hp[N];
  8. int si;
  9. void heap_swap(int a, int b)
  10. {
  11. swap(ph[hp[a]], ph[hp[b]]);
  12. swap(hp[a], hp[b]);
  13. swap(h[a], h[b]);
  14. }
  15. void down(int u) {
  16. int t = u;
  17. if (u * 2 <= si && h[u * 2] < h[t]) t = u * 2;
  18. if (u * 2 + 1 <= si && h[u * 2 + 1] < h[t]) t = u * 2 + 1;
  19. if (u != t) {
  20. heap_swap(u, t);
  21. down(t);
  22. }
  23. }
  24. void up(int u) {
  25. while (u / 2 && h[u / 2] > h[u])
  26. {
  27. heap_swap(u / 2, u);
  28. u /= 2;
  29. }
  30. }
  31. int main() {
  32. ios::sync_with_stdio(false);
  33. cin >> n;
  34. while (n--) {
  35. char op[4];
  36. cin >> op;
  37. int k, x;
  38. if (!strcmp(op, "I"))
  39. {
  40. cin >> x;
  41. m++;
  42. si++;
  43. ph[m] = si;
  44. hp[si] = m;
  45. h[si] = x;
  46. up(si);
  47. } else if (!strcmp(op, "PM"))
  48. {
  49. cout << h[1] << endl;
  50. } else if (!strcmp(op, "DM"))
  51. {
  52. heap_swap(1, si);
  53. si--;
  54. down(1);
  55. } else if (!strcmp(op, "D"))
  56. {
  57. cin >> k;
  58. k = ph[k];
  59. heap_swap(k, si);
  60. si--;
  61. up(k), down(k);
  62. } else
  63. {
  64. cin >> k >> x;
  65. k = ph[k];
  66. h[k] =x;
  67. up(k), down(k);
  68. }
  69. }
  70. return 0;
  71. }