原题地址:https://www.luogu.org/problemnew/show/P3384

题目简述

给定一些序列(没有重复数字),每个序列支持:

给定一些数k(对于每个序列不重复),每次在序列里找到最接近k的数删除(如果有2个数字与k差一样,即分别是k-b和k+b,则选择较小的k-b),累加与k的差,输出。


思路

其实关键就是维护一个有序序列,支持插入,查询前继后继,删除指定数字。

自然我们会想到手打平衡树,Treap/Splay皆可。(这里只有旋转实现的Treap,非旋Treap(Split+Merge)和Splay日后加上)

Tips:为了防止越界等问题以及方便提取区间(尤其是Splay),序列前后一般塞上一个-INF和INF

然而作为C++选手,我们应该妙用STL。set可以实现这样的功能,内部是红黑树实现的也很快。


代码

  1. 旋转实现的Treap(160ms,3.03MB)
#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <cmath>
#include <ctime>
#include <algorithm>
using namespace std;
const int INF=1e9;
inline int randad(){
static int seed=114514;
return seed=int(seed*48271LL%2147483647);//48271使得随机数有完全周期,即2147483647内取遍不重复
}
int delta=0;
struct node {
int pri,val,ch[2],size,tot;
//pri:Treap的随机数
//val:数字
//ch[0,1]:左孩子右孩子
//size:以该节点为根的子树里有几个数字
//tot:这个数字出现了几次(本题无用)
}T[111111];
int k,size=0,ANS,ans;//k:根节点,size:树的大小,ANS:临时,ans:赶走了几个人
void update(int k){T[k].size=T[T[k].ch[0]].size+T[T[k].ch[1]].size+T[k].tot;}
void rturn(int &k)//右旋,把k旋到右边,k左孩子提到根
{
int t=T[k].ch[0];
T[k].ch[0]=T[t].ch[1];
T[t].ch[1]=k;
T[t].size=T[k].size;
update(k);
k=t;
}
void lturn(int &k)//左旋,把k旋到左边,k右孩子提到根
{
int t=T[k].ch[1];
T[k].ch[1]=T[t].ch[0];
T[t].ch[0]=k;
T[t].size=T[k].size;
update(k);
k=t;
}
void ins(int &k,int val) //插入
{
if (k==0) {
size++;
k=size;
T[k].pri=randad();
T[k].val=val;
T[k].size=T[k].tot=1;
return ;
}
T[k].size++;
if (T[k].val==val) T[k].tot++;
else if (val>T[k].val) {
ins(T[k].ch[1],val);
if (T[T[k].ch[1]].pri<T[k].pri) lturn(k);
} else {
ins(T[k].ch[0],val);
if (T[T[k].ch[0]].pri<T[k].pri) rturn(k);
}
}
void del(int &k,int val)//删除值为val的数
{
if (k==0) return ;
if (T[k].val==val) {
if (T[k].tot>1) {
T[k].tot--;
T[k].size--;
return ;
}
if (T[k].ch[0]==0||T[k].ch[1]==0) k=T[k].ch[0]+T[k].ch[1];
else if(T[T[k].ch[0]].pri<T[T[k].ch[1]].pri) rturn(k),del(k,val);
else lturn(k),del(k,val);
} else if(val>T[k].val) T[k].size--,del(T[k].ch[1],val);
else T[k].size--,del(T[k].ch[0],val);
}
int xth(int &k,int x)//查询第x小的数是什么
{
if(k==0||x==0)return 0;
if(x<=T[T[k].ch[0]].size) return xth(T[k].ch[0],x);
else if(x>T[T[k].ch[0]].size+T[k].tot) return xth(T[k].ch[1],x-T[T[k].ch[0]].size-T[k].tot);
else return T[k].val;
}
int find(int &k,int x)//查询第x小数在树中位置
{
if (k==0||x==0) return 0;
if(x<=T[T[k].ch[0]].size)return find(T[k].ch[0],x);
if(x==T[T[k].ch[0]].size+1)return k;
return find(T[k].ch[1],x-T[T[k].ch[0]].size-1);
}
void pre(int k,int x)//查询不比x大的且最接近x的数所在位置(x前继)
{
if(k==0)return;
if(T[k].val<x) ANS=k,pre(T[k].ch[1],x);
else pre(T[k].ch[0],x);
}
void next(int k,int x)//查询不比x小的且最接近x的数所在位置(x后继)
{
if(k==0)return;
if(T[k].val>x) ANS=k,next(T[k].ch[0],x);
else next(T[k].ch[1],x);
}
void Catch(int num)//匹配宠物和饲养人
{
int a,b;
pre(k,num),a=T[ANS].val;
next(k,num), b=T[ANS].val; if(num-a<=b-num && a != -INF) {
ans += num-a;
del(k,a);
} else {
ans += b-num;
del(k,b);
}
ans %= 1000000;
}
int main()
{
int n;
scanf("%d", &n);
int cur;
ins(k,-INF),ins(k,INF);
for(int i = 1; i <= n; i++) {
int a, b;
scanf("%d%d", &a, &b);
if(T[k].size == 2) {
cur=a;//cur:当前是宠物等人认领还是人在等着接受宠物(看原题,不然谁看得懂啊= =)
ins(k,b);
} else if(a == cur) ins(k,b);
else Catch(b);
}
printf("%d\n", ans);
return 0;
return 0;
}
  1. set实现(304ms,2.57MB)
#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <cmath>
#include <ctime>
#include <set>
#include <algorithm>
using namespace std;
const int maxn = 1111111;
const int INF = 1000000000;
int n, ans;
set <int> s;
void find(int x) {
set<int>::iterator left=--s.lower_bound(x),right=s.lower_bound(x);//lower_bound的实现是二分查找,迭代器指向不比x小的且最接近x的数的位置,所以left就是前继,right就是后继
if(x-*left<=*right-x&&*left!=-INF) {
ans+=x-*left;
s.erase(left);
} else {
ans+=*right-x;
s.erase(right);
}
ans%=1000000;
}
int main()
{
scanf("%d",&n);
int cur;
s.insert(-INF),s.insert(INF);
for(int i=1;i<=n;i++) {
int a,b;
scanf("%d%d", &a, &b);
if(s.size()==2) {
cur=a;
s.insert(b);
} else if(a==cur) s.insert(b);
else find(b);
}
printf("%d\n", ans);
return 0;
}

洛谷:P3384 [HNOI2004]宠物收养场的更多相关文章

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

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

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

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

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

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

  4. 洛谷P2286 [HNOI2004]宠物收养所 [STL,平衡树]

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

  5. 洛谷$P$2286 宠物收养场 $[HNOI2004]$ $splay$

    正解:$splay$ 解题报告: 传送门! $splay$板子,,,? 先考虑这题要实现些什么东西嘛$QwQ$ 其实只要实现一个东西?就查询数列中与给定数字相差最小的数,显然用$splay$查询前驱后 ...

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

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

  7. P2286 [HNOI2004]宠物收养场

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

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

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

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

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

随机推荐

  1. 第10章 文档对象模型DOM 10.3 Element类型

    Element 类型用于表现 XML或 HTML元素,提供了对元素标签名.子节点及特性的访问. 要访问元素的标签名,可以使用 nodeName 属性,也可以使用 tagName 属性:这两个属性会返回 ...

  2. 牛客19985 HAOI2011向量(裴属定理,gcd)

    https://ac.nowcoder.com/acm/problem/19985 看到标签“裴属定理”就来做下,很眼熟,好像小学奥数学过.. 题意:给你a,b,x,y,你可以任意使用(a,b), ( ...

  3. 51nod 1218 最长递增子序列 V2(dp + 思维)

    题目链接:https://www.51nod.com/onlineJudge/questionCode.html#!problemId=1218 题解:先要确定这些点是不是属于最长递增序列然后再确定这 ...

  4. 如何设计web系统的监控

    如何使用httpclient设计开发一套web系统监控? 我之前有实现和写过关于运维和开发两个层面的监控系统的文章(https://www.cnblogs.com/zhikou/p/8576891.h ...

  5. 关于ASP.NET中WEBAPI中POST请求中FromBody修饰的string类型的参数服务器端获取不到值FromBody空值的简单解决方法

    其实解决办法很简单,就是POST请求的时候,来自实体的参数,content-type:application/x-www-form-urlencoded情况下,是默认按照键值对来解析的,比如param ...

  6. Spring Cloud Alibaba | 微服务分布式事务之Seata

    Spring Cloud Alibaba | 微服务分布式事务之Seata 本篇实战所使用Spring有关版本: SpringBoot:2.1.7.RELEASE Spring Cloud:Green ...

  7. mysql之innodb存储引擎---BTREE索引实现

    在阅读本篇文章可能需要一些B树和B+树的基础 一.B树和B+树的区别 1.B树的键值不会出现多次,而B+树的键值一定会出现在叶子节点上,而且在非叶子节点也可能会重复出现2.B数存储真实数据,B+数叶子 ...

  8. 四大组件初始之Broadcast

    在进行应用设计时,需要获取很多环境参数,像电量,音量,亮度,网络等.相比较每次去询问android这些信息改变了吗.让Android告诉我们,这些信息改变了更加合理.只要这些信息改变,Android通 ...

  9. 策略模式+注解 干掉业务代码中冗余的if else...

    前言: 之前写过一个工作中常见升级模式-策略模式 的文章,里面讲了具体是怎样使用策略模式去抽象现实中的业务代码,今天来拿出实际代码来写个demo,这里做个整理来加深自己对策略模式的理解.   一.业务 ...

  10. 在nginx日志access log可以记录POST请求的参数值

    1)      在nginx日志access log可以记录POST请求的参数值 实现程度:日志中可以显示POST请求所提交的参数值 问题: 日志中文显示十六进制(在配置文件中配置中文也无效) 没有对 ...