首页 > 其他分享 >平衡树板子

平衡树板子

时间:2023-08-17 23:56:29浏览次数:20  
标签:cnt return int sum update else 平衡 板子

替罪羊

#include <algorithm>
#include <iostream>

using namespace std;

const int MaxN = 4e5 + 10;
const double eps = 0.75;

int d[MaxN], l[MaxN], r[MaxN], cnt[MaxN], sum[MaxN], sz[MaxN], a[MaxN], tot, n, root, len;

void update(int x) {  // 更新
  sum[x] = sum[l[x]] + sum[r[x]] + cnt[x];
  sz[x] = sz[l[x]] + sz[r[x]] + 1;
}

bool Check(int x) {  // 判断是否需要重构
  return cnt[x] && 1.0 * max(sz[l[x]], sz[r[x]]) > eps * sz[x];
}

void dfs(int x) {  // 中序遍历
  if (!x) {
    return;
  }
  dfs(l[x]);
  cnt[x] && (a[++len] = x);
  dfs(r[x]);
}

int build(int pl, int pr) {  // 二分重构
  if (pl > pr) {
    return 0;
  }
  int mid = (pl + pr) >> 1;
  l[a[mid]] = build(pl, mid - 1);
  r[a[mid]] = build(mid + 1, pr);
  update(a[mid]);
  return a[mid];
}

int G(int k) {
  len = 0;
  dfs(k);
  return k = build(1, len);
}

void insert(int &k, int x) {  // 添加
  if (!k) {
    k = ++tot;
    (!root) && (root = tot);
    d[tot] = x, l[tot] = r[tot] = 0, sum[tot] = cnt[tot] = sz[tot] = 1;
    return;
  }
  if (d[k] == x) {
    cnt[k]++;
  } else if (d[k] < x) {
    insert(r[k], x);
  } else {
    insert(l[k], x);
  }
  update(k);
  if (Check(k)) {
    k = G(k);
  }
}

void delet(int &k, int x) {  // 删除
  if (!k) {
    return;
  }
  if (d[k] == x) {
    cnt[k] && (cnt[k]--);
  } else if (d[k] < x) {
    delet(r[k], x);
  } else {
    delet(l[k], x);
  }
  update(k);
  if (Check(k)) {
    k = G(k);
  }
}

int At(int k, int x) {  // @
  if (!k) {
    return 0;
  }
  if (sum[l[k]] < x && x <= sum[l[k]] + cnt[k]) {
    return d[k];
  } else if (sum[l[k]] + cnt[k] < x) {
    return At(r[k], x - sum[l[k]] - cnt[k]);
  }
  return At(l[k], x);
}

int upbd(int k, int x) {  // 大于
  if (!k) {
    return 1;
  }
  if (d[k] == x && cnt[k]) {
    return sum[l[k]] + cnt[k] + 1;
  } else if (x < d[k]) {
    return upbd(l[k], x);
  }
  return upbd(r[k], x) + sum[l[k]] + cnt[k];
}

int upgrt(int k, int x) {  // 小于
  if (!k) {
    return 0;
  }
  if (d[k] == x && cnt[k]) {
    return sum[l[k]];
  } else if (d[k] < x) {
    return upgrt(r[k], x) + sum[l[k]] + cnt[k];
  }
  return upgrt(l[k], x);
}

int p(int x) {  // 前驱
  return At(root, upgrt(root, x));
}

int h(int x) {  // 后继
  return At(root, upbd(root, x));
}

int main() {
  cin >> n;
  for (int op, x; n; n--) {
    cin >> op >> x;
    if (op == 1) {
      insert(root, x);
    } else if (op == 2) {
      delet(root, x);
    } else if (op == 3) {
      cout << upgrt(root, x) + 1 << '\n';
    } else if (op == 4) {
      cout << At(root, x) << '\n';
    } else if (op == 5) {
      cout << p(x) << '\n';
    } else {
      cout << h(x) << '\n';
    }
  }
  return 0;
}

旋转Treap

#include <ctime>
#include <iostream>
#include <random>

using namespace std;

const int MaxN = 1e5 + 10;

struct Node {
  int d, v, l, r, sum, cnt;
} w[MaxN];

int n, root, tot;

void update(int x) {
  w[x].sum = w[w[x].l].sum + w[w[x].r].sum + w[x].cnt;
}

void left(int &k) {
  int p = w[k].l;
  w[k].l = w[p].r, w[p].r = k, k = p;
  update(w[k].r), update(k);
}

void right(int &k) {
  int p = w[k].r;
  w[k].r = w[p].l, w[p].l = k, k = p;
  update(w[k].l), update(k);
}

void insert(int &k, int x) {
  if (!k) {
    k = ++tot;
    w[k] = {x, rand(), 0, 0, 1, 1};
    return;
  }
  if (w[k].d == x) {
    w[k].cnt++;
  } else if (w[k].d < x) {
    insert(w[k].r, x);
    if (w[w[k].r].v < w[k].v) {
      right(k);
    }
  } else {
    insert(w[k].l, x);
    if (w[w[k].l].v < w[k].v) {
      left(k);
    }
  }
  update(k);
}

void delet(int &k, int x) {
  if (!k) {
    return;
  }
  if (w[k].d == x) {
    if (w[k].cnt) {
      w[k].cnt--, update(k);
    } else if (w[k].l || w[k].r) {
      if (!w[k].r || w[w[k].l].d > w[w[k].r].d) {
        left(k), delet(w[k].l, x);
      } else {
        right(k), delet(w[k].r, x);
      }
      update(k);
    } else {
      k = 0;
    }
  }
  if (w[k].d < x) {
    delet(w[k].r, x);
  } else {
    delet(w[k].l, x);
  }
  update(k);
}

int upbd(int k, int x) {
  if (!k) {
    return 1;
  }
  if (w[k].d == x) {
    return w[w[k].l].sum + w[k].cnt + 1;
  } else if (w[k].d < x) {
    return upbd(w[k].r, x) + w[w[k].l].sum + w[k].cnt;
  }
  return upbd(w[k].l, x);
}
int upgrt(int k, int x) {
  if (!k) {
    return 0;
  }
  if (w[k].d == x) {
    return w[w[k].l].sum;
  } else if (x < w[k].d) {
    return upgrt(w[k].l, x);
  }
  return upgrt(w[k].r, x) + w[w[k].l].sum + w[k].cnt;
}

int At(int k, int x) {
  if (!k) {
    return 0;
  }
  if (w[w[k].l].sum < x && x <= w[w[k].l].sum + w[k].cnt) {
    return w[k].d;
  } else if (w[w[k].l].sum + w[k].cnt < x) {
    return At(w[k].r, x - w[w[k].l].sum - w[k].cnt);
  }
  return At(w[k].l, x);
}

int main() {
  srand(time(NULL));
  cin >> n;
  for (int op, x; n; n--) {
    cin >> op >> x;
    if (op == 1) {
      insert(root, x);
    } else if (op == 2) {
      delet(root, x);
    } else if (op == 3) {
      cout << upgrt(root, x) + 1 << '\n';
    } else if (op == 4) {
      cout << At(root, x) << '\n';
    } else if (op == 5) {
      cout << At(root, upgrt(root, x)) << '\n';
    } else {
      cout << At(root, upbd(root, x)) << '\n';
    }
  }
  return 0;
}

标签:cnt,return,int,sum,update,else,平衡,板子
From: https://www.cnblogs.com/ybtarr/p/17639234.html

相关文章

  • 平衡二叉树
    110.平衡二叉树-力扣(LeetCode)确定思路如果左右子树都是平衡二叉树,并且左右子树的高度相差不超过1,那么就是平衡二叉树,如果左子树不是平衡二叉树也就不用对右子树进行递归了确定终止条件应该是遍历到叶子节点,因为叶子节点不能构成二叉树了,因为就没有再往下遍历的必要了——......
  • 代码随想录算法训练营第十七天| 110.平衡二叉树 257. 二叉树的所有路径 404.左叶子
     卡哥建议:迭代法,大家可以直接过,二刷有精力的时候 再去掌握迭代法。  110.平衡二叉树 (优先掌握递归)   卡哥建议:再一次涉及到,什么是高度,什么是深度,可以巩固一下。   题目链接/文章讲解/视频讲解:https://programmercarl.com/0110.%E5%B9%B3%E8%A1%A1%E4%BA%8C%......
  • 二分板子
    1.求最大值最小while(l<=r){  mid=(l+r)>>1;  if(check(mid))ans=mid,r=mid-1;    elsel=mid+1; }例题洛谷p3853路标设置code#include<bits/stdc++.h>usingnamespacestd;intl,n,k,a[100010],r,ll,mid,ans,cnt;boolcheck......
  • 平衡树
    【模板】普通平衡树&【模板】普通平衡树(数据加强版)考虑最简单的平衡树——Treap(Tree+heap),从它的名字上就可以看出它是树和堆结合的产物。那它究竟是怎么样呢?别着急,要研究它,必须研究它的基础版本——BinarySearchTree,二叉搜索树,简称BST。简单来说,它需要满足对于任意一点,它的左......
  • 在感觉的海洋中找寻平衡:幼儿感觉统合训练的探索之旅
    (仅供参考)在我的生活中,我一直关注着孩子们如何在这个充满感觉的世界中找寻他们的位置。特别是那些在处理日常生活中感觉输入信息存在困难的孩子,我看到他们在尝试理解和响应周围环境的感觉信息时的挣扎。于是,我开始探索一种名为“感觉统合训练”(SensoryIntegrationTraining)的方法......
  • luogu P4200 千山鸟飞绝 题解 【一维数组套平衡树】
    目录题目解题思路code题目题目链接解题思路首先,此题有明显的插入、删除、查找,所以必须要使用平衡树。考虑如何使用平衡树维护每个鸟的状态。发现很不方便,因为鸟的位置改变,整个平衡树的值都要修改。考虑针对每个节点开一颗平衡树,这样就有\(3e4\times3e4\)棵树。这显然太多了......
  • SD130T带充电平衡,双节锂电池充电控制芯片
    SD130T是一款完整的双节锂离子电池充电器,带电池正负极反接保护,采用恒定电流/恒定电压线性控制。只需较少的外部元件数目使得SD130T便携式应用的理想选择。SD130T可以适合USB电源和适配器电源工作。由于采用了内部PMOSFET架构,加上防倒充电路,所以不需要外部检测电阻器和隔离二极管......
  • 计算几何の板子
    一精度处理\(eps\)和\(sgn\)constdoubleeps=1e-8;intsgn(doublex){//判断大小if(fabs(x)<eps)return0;elsereturnx<0?-1:1;}二点1点的初始化向量的表示形式上与点完全相同重载点运算符,支持向量的四种运算structPoint{doublex,y;Poi......
  • 平衡二叉查找树--splay
    splay树,又称伸展树,是一种平衡二叉查找树,通过不断把每个节点旋转到根节点能够在O(logN)的时间内完成插入、查找以及删除的操作,并且能保持平衡不会退化成链一、关于二叉查找树首先,二叉查找树肯定是个二叉树(废话),每个节点的左子节点的值小于该节点的值小于右子节点的值。这......
  • 平衡树从入门到入土【待更新】
    O.写在前面本文的题目叫「平衡树从入门到入土」。因为我想让每一个学过树形结构的同学,都能够学会这种十分重要的数据结构。不论是上课睡觉没有听还是准备提前预习的同学,都能从这篇文章受益。平衡树的核心思想在于如何保证「平衡」——显然,也是最难理解的。大部分平衡树是通过「......