[luogu2286][HNOI2004]宠物收养场【平衡树】
前言
这一篇题解并不是为了讲什么算法,只是总结一下平衡树在OI考试中的注意事项。
题意简化(给不想看题目的小伙伴们一点福利)
给你两堆数,每一次给你一个数,每一次在另外一堆数中找到这个数的前缀后继,删去前驱后继中较靠近的,得到了分数为两个数的差的绝对值。请你让这个分数最小。
(题意简化的应该不能在简化了吧qwq)
做法1&&2&&3(非正常做法)
我们都知道,所有的平衡树的题目都可以用不定长数组vector
和不允许重复元素的set
或者是允许重复元素的muliset
来实现。
这个东西在考场上是救命的,如果你剩下的时间不多了,那么是在不行就用以上的办法来偏分。
分析一下vector
和set
和muliset
的优缺点。
不定长数组vector
实现起来非常的简单,只要你熟悉指针和vector
的正常操作。
但是vector很容易溢出,长度一大,很有可能就RE,那个时候想哭都没时间哭了。
#include <bits/stdc++.h>
using namespace std;
int n;
vector<int>v;
int main() {
scanf("%d",&n);
for(int i=1;i<=n;i++) {
int op=0,x=0;
scanf("%d%d",&op,&x);
if(op==1) v.insert(upper_bound(v.begin(),v.end(),x),x);
else if(op==2) v.erase(lower_bound(v.begin(),v.end(),x));
else if(op==3) printf("%d\n",lower_bound(v.begin(),v.end(),x)-v.begin()+1);
else if(op==4) printf("%d\n",v[x-1]);
else if(op==5) printf("%d\n",*--lower_bound(v.begin(),v.end(),x));
else if(op==6) printf("%d\n",*upper_bound(v.begin(),v.end(),x));
}
return 0;
}
实现非常的简单,但是需要注意指针的变换。
但是这一道题目我们用vector,蒟蒻我用了差不多5s才跑出大的数据。(数据从LOJ上来的)
所以set
和muliset
可以更加快速的完成我们的任务。
set
差别并不是太大,一个可以实现没有重复的,一个实现有重复的。
来自chhokmah的实测,set比muliset要快。
所以总结一下:
- vector好写,但是容易错,不推荐使用。
- set可以实现无重复,推荐使用。
- muliset可以实现有重复,推荐使用。
做法4正常的平衡树
这里以treap为例。
简单介绍一下treap,treap是tree和heap的结合,每一次我们需要用自己给节点附加的rd
值来维护平衡树的平衡性。
代码实现非常的简单,但是我打的比较冗长。
那么再回到这一道题目,如果我们只需要建立两个平衡树。(其实一棵就足够了,因为一棵有节点的时候另外一棵一定是没有节点的。)
每一次找前驱和后继,判断更加接近的那一个,更新答案,并删除前驱或者是后继。
如果树为空或者是己方的树有节点,那么就直接插入。
#include <bits/stdc++.h>
#define N 80005
#define mod 1000000
#define ll long long
#define inf 0x3f3f3f3f
using namespace std;
template <typename T>
inline void read(T &x) {
x = 0; T fl = 1; char ch = 0;
for (; ch < '0' || ch > '9'; ch = getchar())
if (ch == '-') fl = -1;
for (; ch >= '0' && ch <= '9'; ch = getchar())
x = (x << 1) + (x << 3) + (ch ^ 48);
x *= fl;
}
struct Treap {
int tot, rt;
struct Node {
int cnt, sz, rd, ch[2], val;
void Init (int Val) { val = Val; ch[0] = ch[1] = 0; cnt = sz = 1; rd = rand() % 100; }
} tr[N];
Treap() { tot = 0; memset(tr, 0, sizeof(tr)); }
void pushup (int nod) { tr[nod].sz = tr[tr[nod].ch[0]].sz + tr[tr[nod].ch[1]].sz + tr[nod].cnt; }
void rotate(int &nod, int d) {
int k = tr[nod].ch[d ^ 1]; tr[nod].ch[d ^ 1] = tr[k].ch[d]; tr[k].ch[d] = nod;
pushup(nod); pushup(k); nod = k;
}
void ins(int &nod, int val) {
if (!nod) nod = ++ tot, tr[nod].Init(val);
else if (val == tr[nod].val) tr[nod].sz ++, tr[nod].cnt ++;
else {
int d = (val > tr[nod].val);
ins(tr[nod].ch[d], val);
if (tr[nod].rd < tr[tr[nod].ch[d]].rd) rotate(nod, d ^ 1);
pushup(nod);
}
}
void del(int &nod, int val) {
if (!nod) return;
if (val < tr[nod].val) del(tr[nod].ch[0], val);
else if (val > tr[nod].val) del(tr[nod].ch[1], val);
else {
if (!tr[nod].ch[0] && !tr[nod].ch[1]) {tr[nod].sz --, tr[nod].cnt --; if (tr[nod].cnt == 0) nod = 0;}
else if (tr[nod].ch[0] && !tr[nod].ch[1]) { rotate(nod, 1) ; del(tr[nod].ch[1], val);}
else if (!tr[nod].ch[0] && tr[nod].ch[1]) { rotate(nod, 0); del(tr[nod].ch[0], val); }
else {
int d = tr[tr[nod].ch[0]].rd > tr[tr[nod].ch[1]].rd;
rotate(nod, d); del(tr[nod].ch[d], val);
}
}
}
int pre(int nod, int val) {
if (!nod) return -inf;
if (tr[nod].val > val) return pre(tr[nod].ch[0], val);
else return max(tr[nod].val , pre(tr[nod].ch[1], val));
}
int suc(int nod, int val) {
if (!nod ) return inf;
if (tr[nod].val < val) return suc(tr[nod].ch[1], val);
else return min(tr[nod].val, suc(tr[nod].ch[0], val));
}
}Pet, Cus;
int n;
ll ans = 0ll;
int main () {
srand(19260817);
read(n);
while (n --) {
int opt, x; read(opt); read(x);
if (opt == 0) { // Pet
if (Cus.rt == 0) Pet.ins(Pet.rt, x);
else {
int lst = Cus.pre(Cus.rt, x), nxt = Cus.suc(Cus.rt, x);
if (abs(x - lst) <= abs(nxt - x)) { Cus.del(Cus.rt, lst); ans = (ans + 1ll * abs(x - lst)) % mod; }
else { Cus.del(Cus.rt, nxt); ans = (ans + 1ll * abs(nxt - x)) % mod;}
}
}
else { // Customer
if (Pet.rt == 0) Cus.ins(Cus.rt, x);
else {
int lst = Pet.pre(Pet.rt, x), nxt = Pet.suc(Pet.rt, x);
if (abs(x - lst) <= abs(nxt - x)) { Pet.del(Pet.rt, lst); ans = (ans + 1ll * abs(x - lst)) % mod; }
else { Pet.del(Pet.rt, nxt); ans = (ans + 1ll * abs(nxt - x)) % mod;}
}
}
}
printf("%lld\n", ans % mod);
return 0;
}
[luogu2286][HNOI2004]宠物收养场【平衡树】的更多相关文章
- [HNOI2004]宠物收养场 Treap前驱后继
凡凡开了一间宠物收养场.收养场提供两种服务:收养被主人遗弃的宠物和让新的主人领养这些宠物. 每个领养者都希望领养到自己满意的宠物,凡凡根据领养者的要求通过他自己发明的一个特殊的公式,得出该领养者希望领 ...
- BZOJ1208[HNOI2004]宠物收养场——treap
凡凡开了一间宠物收养场.收养场提供两种服务:收养被主人遗弃的宠物和让新的主人领养这些宠物. 每个领养者都希望领养到自己满意的宠物,凡凡根据领养者的要求通过他自己发明的一个特殊的公式,得出该领养者希望领 ...
- 洛谷 P2286 [HNOI2004]宠物收养场
题目描述 凡凡开了一间宠物收养场.收养场提供两种服务:收养被主人遗弃的宠物和让新的主人领养这些宠物. 每个领养者都希望领养到自己满意的宠物,凡凡根据领养者的要求通过他自己发明的一个特殊的公式,得出该领 ...
- LG_2286_[HNOI2004]宠物收养场
题目描述 凡凡开了一间宠物收养场.收养场提供两种服务:收养被主人遗弃的宠物和让新的主人领养这些宠物. 每个领养者都希望领养到自己满意的宠物,凡凡根据领养者的要求通过他自己发明的一个特殊的公式,得出该领 ...
- P2286 [HNOI2004]宠物收养场
题目描述 凡凡开了一间宠物收养场.收养场提供两种服务:收养被主人遗弃的宠物和让新的主人领养这些宠物. 每个领养者都希望领养到自己满意的宠物,凡凡根据领养者的要求通过他自己发明的一个特殊的公式,得出该领 ...
- 洛谷P2286 [HNOI2004]宠物收养场【Treap】题解+AC代码
题目传送门啦~啦~啦~ 题目描述 凡凡开了一间宠物收养场.收养场提供两种服务:收养被主人遗弃的宠物和让新的主人领养这些宠物. 每个领养者都希望领养到自己满意的宠物,凡凡根据领养者的要求通过他自己发明的 ...
- 洛谷P2286 [HNOI2004]宠物收养场
题目描述 凡凡开了一间宠物收养场.收养场提供两种服务:收养被主人遗弃的宠物和让新的主人领养这些宠物. 每个领养者都希望领养到自己满意的宠物,凡凡根据领养者的要求通过他自己发明的一个特殊的公式,得出该领 ...
- [HNOI2004]宠物收养场 BZOJ1208 splay tree
题目描述 凡凡开了一间宠物收养场.收养场提供两种服务:收养被主人遗弃的宠物和让新的主人领养这些宠物. 每个领养者都希望领养到自己满意的宠物,凡凡根据领养者的要求通过他自己发明的一个特殊的公式,得出该领 ...
- 1208. [HNOI2004]宠物收养场【平衡树-splay】
Description 最近,阿Q开了一间宠物收养所.收养所提供两种服务:收养被主人遗弃的宠物和让新的主人领养这些宠物.每个领养者都希望领养到自己满意的宠物,阿Q根据领养者的要求通过他自己发明的一个特 ...
随机推荐
- PlainElastic.Net
PlainElastic.Net PlainElastic.Net The really plain Elastic Search .Net client. Idea Installation How ...
- mybatis一级缓存详解
mybatis缓存分为一级缓存,二级缓存和自定义缓存.本文重点讲解一级缓存 一:前言 在介绍缓存之前,先了解下mybatis的几个核心概念: * SqlSession:代表和数据库的一次会话,向用户提 ...
- linux不同终端的操作是如何在messages日志中区分的
今天在定位一个问题时,查看message日志,需要知道message日志中的记录分别是哪个Xterm终端操作的.比较了半天才发现原来日志中可以通过pts来进行区分.如下所示: --12T15:::|n ...
- mac 电脑 打开隐藏文件
command +shift +. 第一次是打开,第二次是关闭
- 如何在MAC上运行exe程序
1. 首先下载并运行CrossOver 运行CrossOver需要收费,试用期为14天,运行CrossOver 2. 选择exe应用程序,新建容器,安装exe程序 3.安装成功后,运行exe应用程序启 ...
- 莫烦scikit-learn学习自修第四天【内置训练数据集】
1. 代码实战 #!/usr/bin/env python #!_*_ coding:UTF-8 _*_ from sklearn import datasets from sklearn.linea ...
- 《Tensorflow从入门到精通》
第一 开发环境搭建 1. tensorflow的环境搭建 windows下安装cpu版tensorflow: pip install tensorflow 在ubuntu上安装gpu版tensorfl ...
- Essential Phone刷机教程
安装fastboot驱动(Essential-PH1-WindowsDrivers) 下载ADB刷机指令工具:platform-tools(ADB): 进入开发者选项,打开 USB 调试,OEM解锁选 ...
- python基础数据类型--dict 字典
字典 字典是python中唯一的映射类型,采用键值对(key-value)的形式存储数据.python对key进行哈希函数运算,根据计算的结果决定value的存储地址,所以字典是无序存储的,且key必 ...
- ffmpeg 转码命令与ffplay
ffmpeg.exe用于视频的转码. ▫ 最简单的命令 ffmpeg -i input.avi -b:v 640k output.ts 该命令将当前文件夹下的input.avi文件转换为output. ...