/**
problem: http://www.fjutacm.com/Problem.jsp?pid=2492
Splay blog: https://tiger0132.blog.luogu.org/slay-notes
函数介绍:
内部函数:
root为指针, x为数值
bool check(int root):返回当前结点为父节点的左结点还是右结点(0为左结点,1为右结点)
void pushUp(int root):旋转后维护结点信息
void rotate(int root):关键函数,旋转结点
void splay(int root, int target = 0):Splay核心,将root结点旋转至target子结点,target为0则旋转到树根
void find(int x): 将数值为x的结点旋转至树根
int pre(int x):寻找数值为x的结点的前驱结点,返回指针
int succ(int x):寻找数值为x的结点的后继节点,返回指针
外部函数:
void clear():清空平衡树
void insert(T x):插入数值为x的数
int rank(T x):返回数值为x的数为第几小
T preAns(T x):返回刚好比数值x小的数是多少
T succAns(T x):返回刚好比数值x大的数是多少
T kth(int k):返回第k小的数是多少
void remove(T x):删除数值为x的结点,如果有多个则数量-1
T top(T x):如果有数值为x的结点返回x,否则返回其他数
int getAllSize():返回平衡树中有多少个数
**/ #include<stdio.h>
#include<algorithm>
#include<queue>
using namespace std; typedef long long ll;
const ll MOD = ; template<typename T>
class Splay{
const static int MAXN = ;
const static T INF = 0x3f3f3f3f3f3f3f3fLL;
private:
struct Node{
int ch[];
int cnt, size, parent;
T val;
}node[MAXN];
int treeroot, sign, allSize;
queue<int> freeMemory;
bool check(int root){ /// right return 1 else return 0
return node[node[root].parent].ch[] == root;
}
void pushUp(int root){
node[root].size = node[node[root].ch[]].size + node[node[root].ch[]].size + node[root].cnt;
}
void rotate(int root){
int father = node[root].parent, grandpa = node[father].parent, direction = check(root), child = node[root].ch[direction^];
node[father].ch[direction] = child; node[child].parent = father;
node[grandpa].ch[check(father)] = root; node[root].parent = grandpa;
node[root].ch[direction^] = father; node[father].parent = root;
pushUp(father); pushUp(root);
}
void splay(int root, int target = ){ /// if target == 0 then root to treeroot
while(node[root].parent != target){
int father = node[root].parent, grandpa = node[father].parent;
if(grandpa != target){
if(check(root) == check(father)) rotate(father);
else rotate(root);
}
rotate(root);
}
if(!target) treeroot = root;
}
void find(int x){
if(!treeroot) return;
int cur = treeroot;
while(node[cur].ch[x > node[cur].val] && node[cur].val != x){
cur = node[cur].ch[x > node[cur].val];
}
splay(cur);
}
int pre(int x){
find(x);
if(node[treeroot].val < x) return treeroot;
if(!node[treeroot].ch[]) return -;
int cur = node[treeroot].ch[];
while(node[cur].ch[]){
cur = node[cur].ch[];
}
return cur;
}
int succ(int x){
find(x);
if(node[treeroot].val > x) return treeroot;
if(!node[treeroot].ch[]) return -;
int cur = node[treeroot].ch[];
while(node[cur].ch[]){
cur = node[cur].ch[];
}
return cur;
}
public:
void clear(){
sign = ;
insert(INF);
insert(-INF);
allSize = ;
}
void insert(T x){
allSize ++;
int cur = treeroot, preroot = ;
while(cur && node[cur].val != x){
preroot = cur;
cur = node[cur].ch[x > node[cur].val];
}
if(cur){
node[cur].cnt ++;
}else{
if(freeMemory.empty())
cur = ++ sign;
else{
cur = freeMemory.front();
freeMemory.pop();
}
if(preroot) node[preroot].ch[x > node[preroot].val] = cur;
node[cur].val = x;
node[cur].cnt = ;
node[cur].ch[] = node[cur].ch[] = ;
node[cur].size = ;
node[cur].parent = preroot;
}
splay(cur);
}
int rank(T x){
find(x);
return node[node[treeroot].ch[]].size;
}
T preAns(T x){
return node[pre(x)].val;
}
T succAns(T x){
return node[succ(x)].val;
}
T kth(int k){
k ++;
int cur = treeroot;
while(){
if(node[cur].ch[] && k <= node[node[cur].ch[]].size){
cur = node[cur].ch[];
}else if(k > node[node[cur].ch[]].size + node[cur].cnt){
k -= node[node[cur].ch[]].size + node[cur].cnt;
cur = node[cur].ch[];
}else{
return node[cur].val;
}
}
}
void remove(T x){
allSize --;
int last = pre(x), next = succ(x);
splay(last), splay(next, last);
int del = node[next].ch[];
if(node[del].cnt > ){
node[del].cnt --;
splay(del);
}else{
freeMemory.push(node[next].ch[]);
node[next].ch[] = ;
}
}
T top(T x){
find(x);
return node[treeroot].val;
}
int getAllSize(){
return allSize;
}
}; Splay<ll> splay; int main(){
int n;
ll ans = ;
bool type = ;
scanf("%d", &n);
splay.clear();
while(n --){
int a;
ll b;
scanf("%d%lld", &a, &b);
if(a){
if(type || splay.getAllSize() == ){
splay.insert(b);
type = ;
}
else{
ll pre = splay.preAns(b), mid = splay.top(b), succ = splay.succAns(b);
ll choose;
if(abs(pre - b) <= abs(mid - b)){
choose = pre;
}else{
choose = mid;
}
if(abs(choose - b) > abs(succ - b)){
choose = succ;
}
ans = (ans + abs(choose - b)) % MOD;
splay.remove(choose);
}
}else{
if(!type || splay.getAllSize() == ){
splay.insert(b);
type = ;
}
else{
ll pre = splay.preAns(b), mid = splay.top(b), succ = splay.succAns(b);
ll choose;
if(abs(pre - b) <= abs(mid - b)){
choose = pre;
}else{
choose = mid;
}
if(abs(choose - b) > abs(succ - b)){
choose = succ;
}
ans = (ans + abs(choose - b)) % MOD;
splay.remove(choose);
}
}
}
printf("%lld\n", ans);
return ;
}

fjutacm 2492 宠物收养所 : Splay 模板 O(nlogn)的更多相关文章

  1. BZOJ 1208 [HNOI2004]宠物收养所 | SPlay模板题

    题目: 洛谷也能评 题解: 记录一下当前树维护是宠物还是人,用Splay维护插入和删除. 对于任何一次询问操作都求一下value的前驱和后继(这里前驱和后继是可以和value相等的),比较哪个差值绝对 ...

  2. HNOI2004宠物收养所(splay维护二叉搜索树模板题)

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

  3. 【BZOJ1208】[HNOI2004]宠物收养所 Splay

    还是模板题,两颗splay,找点删即可. #include <iostream> #include <cstdio> #include <cstdlib> #def ...

  4. [bzoj1208][HNOI2004]宠物收养所——splay

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

  5. 【BZOJ-1208】宠物收养所 Splay

    1208: [HNOI2004]宠物收养所 Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 6638  Solved: 2601[Submit][Sta ...

  6. BZOJ 1208 宠物收养所 | 平衡树模板题

    BZOJ 1208 宠物收养所 我犯过的错误:删除一个节点后没有update新的根节点,导致size错了! #include <cstdio> #include <cmath> ...

  7. Bzoj 1208: [HNOI2004]宠物收养所(splay)

    1208: [HNOI2004]宠物收养所 Time Limit: 10 Sec Memory Limit: 162 MB Description 最近,阿Q开了一间宠物收养所.收养所提供两种服务:收 ...

  8. bzoj 1208 宠物收养所--splay

    这个题也是单点维护,不管来的是人还是狗,只要num=0就插入,否则就删除. // File Name: ACM/bzoj/1208.cpp // Author: Zlbing // Created T ...

  9. BZOJ1208 [HNOI2004]宠物收养所 splay

    原文链接http://www.cnblogs.com/zhouzhendong/p/8085803.html 题目传送门 - BZOJ1208 题意概括 有两种数,依次加入. 规则为下: 如果当前剩余 ...

随机推荐

  1. PHP file_put_contents() 函数

    file_put_contents() 函数把一个字符串写入文件中. 与依次调用 fopen(),fwrite() 以及 fclose() 功能一样. 语法如下 file_put_contents(f ...

  2. 转载:解决IE下a标签会触发window.onbeforeunload的问题

    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <hea ...

  3. IO流之转换流

    转换流 OutputStreamWriter类 查阅OutputStreamWriter的API介绍,OutputStreamWriter 是字符流通向字节流的桥梁:可使用指定的字符编码表,将要写入流 ...

  4. BZOJ2535: [Noi2010]Plane 航空管制2(拓扑排序 贪心)

    题意 题目链接 Sol 非常妙的一道题. 首先不难想到拓扑排序,但是直接对原图按\(k\)从小到大拓扑排序是错的.因为当前的\(k\)大并不意味着后面的点\(k\)也大 但是在反图上按\(k\)从大到 ...

  5. php有经纬度计算距离

    /** *  @desc 根据两点间的经纬度计算距离 *  @param float $lat 纬度值 *  @param float $lng 经度值 */  function getDistanc ...

  6. webstorm 配置Vue.js 语法提示

    标签属性 v-text v-html v-once v-if v-show v-else v-for v-on v-bind v-model v-ref v-el v-pre v-cloak v-on ...

  7. yanxin8文章归档

    文章归档 - 2015年四月 (共21篇文章) 26日: 14443协议的CRC_A和CRC_B (0条评论) 25日: 百度钱包-1分钱5元话费 (0条评论) 22日: 驾照考试总结 (0条评论) ...

  8. Java实现队列结构的详细代码

    一.什么是队列结构 一种线性结构,具有特殊的运算法则[只能在一端(队头)删除,在另一端(队尾)插入]. 分类: 顺序队列结构 链式队列结构 基本操作: 入队列 出队列 二.准备数据 static fi ...

  9. mvc4站点支持.html

    MVc站点在配置通配符后,还需要配置这个才能支持.html.在自定义的路由中加入.自定义代码就可以支持子定义的html了.

  10. Visual Studio 快捷键汇总

    常见方法: 强迫智能感知:Ctrl+J.智能感知是Visual Studio最大的亮点之一,选择Visual Studio恐怕不会没有这个原因.  撤销:Ctrl+Z.除非你是天才,那么这个快捷键也是 ...