fjutacm 2492 宠物收养所 : Splay 模板 O(nlogn)
/**
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)的更多相关文章
- BZOJ 1208 [HNOI2004]宠物收养所 | SPlay模板题
题目: 洛谷也能评 题解: 记录一下当前树维护是宠物还是人,用Splay维护插入和删除. 对于任何一次询问操作都求一下value的前驱和后继(这里前驱和后继是可以和value相等的),比较哪个差值绝对 ...
- HNOI2004宠物收养所(splay维护二叉搜索树模板题)
描述 最近,阿Q开了一间宠物收养所.收养所提供两种服务:收养被主人遗弃的宠物和让新的主人领养这些宠物.每个领养者都希望领养到自己满意的宠物,阿Q根据领养者的要求通过他自己发明的一个特殊的公式,得出该领 ...
- 【BZOJ1208】[HNOI2004]宠物收养所 Splay
还是模板题,两颗splay,找点删即可. #include <iostream> #include <cstdio> #include <cstdlib> #def ...
- [bzoj1208][HNOI2004]宠物收养所——splay
题目大意 Description 最近,阿Q开了一间宠物收养所.收养所提供两种服务:收养被主人遗弃的宠物和让新的主人领养这些宠物.每个领养者都希望领养到自己满意的宠物,阿Q根据领养者的要求通过他自己发 ...
- 【BZOJ-1208】宠物收养所 Splay
1208: [HNOI2004]宠物收养所 Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 6638 Solved: 2601[Submit][Sta ...
- BZOJ 1208 宠物收养所 | 平衡树模板题
BZOJ 1208 宠物收养所 我犯过的错误:删除一个节点后没有update新的根节点,导致size错了! #include <cstdio> #include <cmath> ...
- Bzoj 1208: [HNOI2004]宠物收养所(splay)
1208: [HNOI2004]宠物收养所 Time Limit: 10 Sec Memory Limit: 162 MB Description 最近,阿Q开了一间宠物收养所.收养所提供两种服务:收 ...
- bzoj 1208 宠物收养所--splay
这个题也是单点维护,不管来的是人还是狗,只要num=0就插入,否则就删除. // File Name: ACM/bzoj/1208.cpp // Author: Zlbing // Created T ...
- BZOJ1208 [HNOI2004]宠物收养所 splay
原文链接http://www.cnblogs.com/zhouzhendong/p/8085803.html 题目传送门 - BZOJ1208 题意概括 有两种数,依次加入. 规则为下: 如果当前剩余 ...
随机推荐
- Java笔记之Scanner先读取一个数字,在读取一行字符串方法分析
问题:大家在学习Java读取数据的时候一般都是使用Scanner方法读取数据,但是其中有一个小问题大家可能不知道, 就是我们在使用scanner的时候如果你先读取一个数字,在读取一行带有空格的字符串, ...
- 静态化HttpClient
实现方法: public class HttpClientHelper { private static HttpClient _client; public static HttpClient Ge ...
- JSP 之 8种HTTP的请求方式 之 页面组成等
HTTP请求的方法: HTTP/1.1协议中共定义了八种方法(有时也叫“动作”),来表明Request-URL指定的资源不同的操作方式 1.OPTIONS 返回服务器针对特定资源所支持的HTTP请 ...
- Stage3--Python控制流程及函数
说在前面: Stage1-Stage4简单介绍一下Python语法,Stage5开始用python实现一些实际应用,语法的东西到处可以查看到,学习一门程序语言的最终目的是应用,而不是学习语法,语法本事 ...
- Hyperledger Fabric SDK use case 1
///////////////////////////////////////////////////////////////////////:End2endAndBackAgainIT 1.Crea ...
- AE常用代码(标注要素、AE中画带箭头的线、如何获得投影坐标、参考坐标、投影方式、FeatureCount注意事项)
手上的电脑已经用了将近三年了,想入手一台Surface Pro,所以计划着把电脑上的资料整理下,部分资料打算发到博客上来,资料有同事.也有自己的.也有来自网络的,来源途径太多,也没法详细注明,请见谅! ...
- Struts2项目问题及解决方式
1. 问题描述如图: 问题解释:意思就是execute()方法写错了. 问题解决: 改正:
- 详解Struts1.x的运行机制及命名规则
Struts1.x 调用一个action的大致流程: 1)首先前端发送 *.do的一个action请求(通过点击表单提交按钮,js 事件等): 2)web.xml 文件通过 *.do 找到 Actio ...
- 多线程(二)~Thread类相关的API介绍
一.线程安全问题: 当我们使用多个线程操作统一方法内的局部变量的时候,每个局部变量在当前线程里都有自己的副本,这种情况是不会出现线程安全问题的.当我们两个线程同时操作全局变量的时候,有可能 ...
- ARM 中可用性集使用的注意事项
Azure 目前有两种部署模型:经典部署模型 (ASM) 和资源管理器 (ARM).如果您之前使用过 ASM 模式下的可用性集,那么很可能在使用 ARM 模式下的可用性集时,会遇到一些问题或者疑惑.这 ...