【传送门】

前言

这一篇题解并不是为了讲什么算法,只是总结一下平衡树在OI考试中的注意事项。

题意简化(给不想看题目的小伙伴们一点福利)

给你两堆数,每一次给你一个数,每一次在另外一堆数中找到这个数的前缀后继,删去前驱后继中较靠近的,得到了分数为两个数的差的绝对值。请你让这个分数最小。
(题意简化的应该不能在简化了吧qwq)


做法1&&2&&3(非正常做法)

我们都知道,所有的平衡树的题目都可以用不定长数组vector和不允许重复元素的set或者是允许重复元素的muliset来实现。
这个东西在考场上是救命的,如果你剩下的时间不多了,那么是在不行就用以上的办法来偏分。
分析一下vectorsetmuliset的优缺点。
不定长数组vector实现起来非常的简单,只要你熟悉指针和vector的正常操作。
但是vector很容易溢出,长度一大,很有可能就RE,那个时候想哭都没时间哭了。

  1. #include <bits/stdc++.h>
  2. using namespace std;
  3. int n;
  4. vector<int>v;
  5. int main() {
  6. scanf("%d",&n);
  7. for(int i=1;i<=n;i++) {
  8. int op=0,x=0;
  9. scanf("%d%d",&op,&x);
  10. if(op==1) v.insert(upper_bound(v.begin(),v.end(),x),x);
  11. else if(op==2) v.erase(lower_bound(v.begin(),v.end(),x));
  12. else if(op==3) printf("%d\n",lower_bound(v.begin(),v.end(),x)-v.begin()+1);
  13. else if(op==4) printf("%d\n",v[x-1]);
  14. else if(op==5) printf("%d\n",*--lower_bound(v.begin(),v.end(),x));
  15. else if(op==6) printf("%d\n",*upper_bound(v.begin(),v.end(),x));
  16. }
  17. return 0;
  18. }

实现非常的简单,但是需要注意指针的变换。
但是这一道题目我们用vector,蒟蒻我用了差不多5s才跑出大的数据。(数据从LOJ上来的)
所以setmuliset可以更加快速的完成我们的任务。
set差别并不是太大,一个可以实现没有重复的,一个实现有重复的。
来自chhokmah的实测,set比muliset要快。
所以总结一下:

  • vector好写,但是容易错,不推荐使用。
  • set可以实现无重复,推荐使用。
  • muliset可以实现有重复,推荐使用。

做法4正常的平衡树

这里以treap为例。
简单介绍一下treap,treap是tree和heap的结合,每一次我们需要用自己给节点附加的rd值来维护平衡树的平衡性。
代码实现非常的简单,但是我打的比较冗长。
那么再回到这一道题目,如果我们只需要建立两个平衡树。(其实一棵就足够了,因为一棵有节点的时候另外一棵一定是没有节点的。)
每一次找前驱和后继,判断更加接近的那一个,更新答案,并删除前驱或者是后继。
如果树为空或者是己方的树有节点,那么就直接插入。

  1. #include <bits/stdc++.h>
  2. #define N 80005
  3. #define mod 1000000
  4. #define ll long long
  5. #define inf 0x3f3f3f3f
  6. using namespace std;
  7. template <typename T>
  8. inline void read(T &x) {
  9. x = 0; T fl = 1; char ch = 0;
  10. for (; ch < '0' || ch > '9'; ch = getchar())
  11. if (ch == '-') fl = -1;
  12. for (; ch >= '0' && ch <= '9'; ch = getchar())
  13. x = (x << 1) + (x << 3) + (ch ^ 48);
  14. x *= fl;
  15. }
  16. struct Treap {
  17. int tot, rt;
  18. struct Node {
  19. int cnt, sz, rd, ch[2], val;
  20. void Init (int Val) { val = Val; ch[0] = ch[1] = 0; cnt = sz = 1; rd = rand() % 100; }
  21. } tr[N];
  22. Treap() { tot = 0; memset(tr, 0, sizeof(tr)); }
  23. void pushup (int nod) { tr[nod].sz = tr[tr[nod].ch[0]].sz + tr[tr[nod].ch[1]].sz + tr[nod].cnt; }
  24. void rotate(int &nod, int d) {
  25. int k = tr[nod].ch[d ^ 1]; tr[nod].ch[d ^ 1] = tr[k].ch[d]; tr[k].ch[d] = nod;
  26. pushup(nod); pushup(k); nod = k;
  27. }
  28. void ins(int &nod, int val) {
  29. if (!nod) nod = ++ tot, tr[nod].Init(val);
  30. else if (val == tr[nod].val) tr[nod].sz ++, tr[nod].cnt ++;
  31. else {
  32. int d = (val > tr[nod].val);
  33. ins(tr[nod].ch[d], val);
  34. if (tr[nod].rd < tr[tr[nod].ch[d]].rd) rotate(nod, d ^ 1);
  35. pushup(nod);
  36. }
  37. }
  38. void del(int &nod, int val) {
  39. if (!nod) return;
  40. if (val < tr[nod].val) del(tr[nod].ch[0], val);
  41. else if (val > tr[nod].val) del(tr[nod].ch[1], val);
  42. else {
  43. if (!tr[nod].ch[0] && !tr[nod].ch[1]) {tr[nod].sz --, tr[nod].cnt --; if (tr[nod].cnt == 0) nod = 0;}
  44. else if (tr[nod].ch[0] && !tr[nod].ch[1]) { rotate(nod, 1) ; del(tr[nod].ch[1], val);}
  45. else if (!tr[nod].ch[0] && tr[nod].ch[1]) { rotate(nod, 0); del(tr[nod].ch[0], val); }
  46. else {
  47. int d = tr[tr[nod].ch[0]].rd > tr[tr[nod].ch[1]].rd;
  48. rotate(nod, d); del(tr[nod].ch[d], val);
  49. }
  50. }
  51. }
  52. int pre(int nod, int val) {
  53. if (!nod) return -inf;
  54. if (tr[nod].val > val) return pre(tr[nod].ch[0], val);
  55. else return max(tr[nod].val , pre(tr[nod].ch[1], val));
  56. }
  57. int suc(int nod, int val) {
  58. if (!nod ) return inf;
  59. if (tr[nod].val < val) return suc(tr[nod].ch[1], val);
  60. else return min(tr[nod].val, suc(tr[nod].ch[0], val));
  61. }
  62. }Pet, Cus;
  63. int n;
  64. ll ans = 0ll;
  65. int main () {
  66. srand(19260817);
  67. read(n);
  68. while (n --) {
  69. int opt, x; read(opt); read(x);
  70. if (opt == 0) { // Pet
  71. if (Cus.rt == 0) Pet.ins(Pet.rt, x);
  72. else {
  73. int lst = Cus.pre(Cus.rt, x), nxt = Cus.suc(Cus.rt, x);
  74. if (abs(x - lst) <= abs(nxt - x)) { Cus.del(Cus.rt, lst); ans = (ans + 1ll * abs(x - lst)) % mod; }
  75. else { Cus.del(Cus.rt, nxt); ans = (ans + 1ll * abs(nxt - x)) % mod;}
  76. }
  77. }
  78. else { // Customer
  79. if (Pet.rt == 0) Cus.ins(Cus.rt, x);
  80. else {
  81. int lst = Pet.pre(Pet.rt, x), nxt = Pet.suc(Pet.rt, x);
  82. if (abs(x - lst) <= abs(nxt - x)) { Pet.del(Pet.rt, lst); ans = (ans + 1ll * abs(x - lst)) % mod; }
  83. else { Pet.del(Pet.rt, nxt); ans = (ans + 1ll * abs(nxt - x)) % mod;}
  84. }
  85. }
  86. }
  87. printf("%lld\n", ans % mod);
  88. return 0;
  89. }

[luogu2286][HNOI2004]宠物收养场【平衡树】的更多相关文章

  1. [HNOI2004]宠物收养场 Treap前驱后继

    凡凡开了一间宠物收养场.收养场提供两种服务:收养被主人遗弃的宠物和让新的主人领养这些宠物. 每个领养者都希望领养到自己满意的宠物,凡凡根据领养者的要求通过他自己发明的一个特殊的公式,得出该领养者希望领 ...

  2. BZOJ1208[HNOI2004]宠物收养场——treap

    凡凡开了一间宠物收养场.收养场提供两种服务:收养被主人遗弃的宠物和让新的主人领养这些宠物. 每个领养者都希望领养到自己满意的宠物,凡凡根据领养者的要求通过他自己发明的一个特殊的公式,得出该领养者希望领 ...

  3. 洛谷 P2286 [HNOI2004]宠物收养场

    题目描述 凡凡开了一间宠物收养场.收养场提供两种服务:收养被主人遗弃的宠物和让新的主人领养这些宠物. 每个领养者都希望领养到自己满意的宠物,凡凡根据领养者的要求通过他自己发明的一个特殊的公式,得出该领 ...

  4. LG_2286_[HNOI2004]宠物收养场

    题目描述 凡凡开了一间宠物收养场.收养场提供两种服务:收养被主人遗弃的宠物和让新的主人领养这些宠物. 每个领养者都希望领养到自己满意的宠物,凡凡根据领养者的要求通过他自己发明的一个特殊的公式,得出该领 ...

  5. P2286 [HNOI2004]宠物收养场

    题目描述 凡凡开了一间宠物收养场.收养场提供两种服务:收养被主人遗弃的宠物和让新的主人领养这些宠物. 每个领养者都希望领养到自己满意的宠物,凡凡根据领养者的要求通过他自己发明的一个特殊的公式,得出该领 ...

  6. 洛谷P2286 [HNOI2004]宠物收养场【Treap】题解+AC代码

    题目传送门啦~啦~啦~ 题目描述 凡凡开了一间宠物收养场.收养场提供两种服务:收养被主人遗弃的宠物和让新的主人领养这些宠物. 每个领养者都希望领养到自己满意的宠物,凡凡根据领养者的要求通过他自己发明的 ...

  7. 洛谷P2286 [HNOI2004]宠物收养场

    题目描述 凡凡开了一间宠物收养场.收养场提供两种服务:收养被主人遗弃的宠物和让新的主人领养这些宠物. 每个领养者都希望领养到自己满意的宠物,凡凡根据领养者的要求通过他自己发明的一个特殊的公式,得出该领 ...

  8. [HNOI2004]宠物收养场 BZOJ1208 splay tree

    题目描述 凡凡开了一间宠物收养场.收养场提供两种服务:收养被主人遗弃的宠物和让新的主人领养这些宠物. 每个领养者都希望领养到自己满意的宠物,凡凡根据领养者的要求通过他自己发明的一个特殊的公式,得出该领 ...

  9. 1208. [HNOI2004]宠物收养场【平衡树-splay】

    Description 最近,阿Q开了一间宠物收养所.收养所提供两种服务:收养被主人遗弃的宠物和让新的主人领养这些宠物.每个领养者都希望领养到自己满意的宠物,阿Q根据领养者的要求通过他自己发明的一个特 ...

随机推荐

  1. 聊一聊跨域,Vue向Django请求数据的一些问题

    1.做前后端分离 前端使用Vue程序,后端使用Django配合rest-framework. 那么前端Vue通过API接口拿到数据会出现跨域的问题,JSONP只是在get中会用到的,所以这里使用cor ...

  2. JavaWeb连接SQLServer数据库并完成一个登录界面及其功能设计。

    一.JDBC连接SQLserver数据库的步骤: 1.下载SQLserver的JDBC驱动文件——Microsoft JDBC Driver 4.0 for SQL Server 2.例如下载得到的文 ...

  3. 【转】redis-cluster安装配置

    需要三台虚拟机(生产环境是3个物理机),分配静态IP.cluster中共6个节点.3主3从.本文中每个虚拟机上的redis端口:6379 6380. 需要注意的两点: 3个主节点分别位于3台虚拟机上, ...

  4. py使用笔记-pandas函数

    1,nan替换为0df = df(np.nan, 0, regex=True)2.inf替换为0df= df(np.inf, 0.0, regex=True)3.从数据库读取数据到dataframei ...

  5. centos 6.9:device eth0 does not seem to be present

    VMware上安装centos6.9,克隆一个新虚机,网卡不能桥接获得宿主机网络地址. https://blog.csdn.net/xiaobei4929/article/details/405152 ...

  6. Linux 下面 PG 的 uuid-ossp 包安装办法

    1. pgsql 安装 时报错, 如图示: 详细信息为: 执行SQL为: CREATE EXTENSION IF NOT EXISTS "uuid-ossp" 错误纤细信息为: C ...

  7. mybatis两种开发方式

    本文首先讲解从JDBC到mybatis的演变过程,然后是使用mybatis进行开发的两种方式. 一 JDBC的使用及其优化 1.使用JDBC进行数据库操作 加载JDBC驱动: 建立并获取数据库连接: ...

  8. python爬虫scrapy之登录知乎

    下面我们看看用scrapy模拟登录的基本写法: 注意:我们经常调试代码的时候基本都用chrome浏览器,但是我就因为用了谷歌浏览器(它总是登录的时候不提示我用验证码,误导我以为登录时不需要验证码,其实 ...

  9. Java HashMap的put操作(Java1.8)

    https://www.cnblogs.com/JzedyBlogs/p/10208295.html 写得非常好: 这个是Java1.8 ------------------------------- ...

  10. JAVA 变量 数据类型 运算符 知识小结

    ---------------------------------------------------> JAVA 变量 数据类型 运算符 知识小结 <------------------ ...