[SCOI2014]方伯伯的OJ——Splay

2024-01-01 23:10
文章标签 伯伯 splay oj scoi2014

本文主要是介绍[SCOI2014]方伯伯的OJ——Splay,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

题面

  Bzoj3595

解析

  wys讲到用Splay, 但我又一次写成了Spaly

  考虑到n的范围巨大而m的范围是正常的1e5, 显然要动态开点,一个点代表一个区间。但这道题只用一棵平衡树可能不太好做,于是有dalao就写了两棵平衡树, 显然我这种一棵平衡树都要写挂的人是不可能去完成两棵平衡树的,于是可以用map代替其中一棵树。其中map第一关键字为区间的右端点,第二关键字为节点编号,要分裂点的时候先查询分裂的节点, 用lower_bound可以在log的时间内查到, 再分裂节点就行, 显然操作1、2、3需要分裂节点。

  对于操作2,当然先是找到节点,然后旋转到根,查询前驱和后继,分情况讨论删除根,再把序列rk1转到根节点, 把删除的节点挂在左二子上就行。操作3类似,删除根及其之前的操作都和操作2一样,只不过操作3要把rk last转到根节点,把删除的节点挂在右儿子上就行

  细节

  分裂节点时分成了[l, val - 1], [val, val] [val + 1, r]三个区间,要注意判断[l, val - 1], [val + 1, r]两个区间是否存在

  0号节点的右儿子要赋成root, 删除节点时要更新(这个我调了2个小时)

  代码:

#include<bits/stdc++.h>
using namespace std;
const int maxn = 500005;template<class T> void read(T &re)
{re=0;T sign=1;char tmp;while((tmp=getchar())&&(tmp<'0'||tmp>'9')) if(tmp=='-') sign=-1;re=tmp-'0';while((tmp=getchar())&&(tmp>='0'&&tmp<='9')) re=(re<<3)+(re<<1)+(tmp-'0');re*=sign;
}int n, m, res, root, tot;
map<int,int> mp;struct splay_tree{int l, r, s[2], fa, siz;
}tr[maxn];int Newnode(int l, int r, int f)
{int ret = ++tot;tr[ret].l = l;tr[ret].r = r;tr[ret].fa = f;tr[ret].siz = r - l + 1;return ret;
}void update(int x)
{int ls = tr[x].s[0], rs = tr[x].s[1];tr[x].siz = tr[ls].siz + tr[rs].siz + tr[x].r - tr[x].l + 1;
}void Rotate(int x)
{int y = tr[x].fa, z = tr[y].fa, k = (tr[y].s[1] == x), w = (tr[z].s[1] == y), son = tr[x].s[k^1];tr[y].s[k] = son;tr[son].fa = y;tr[x].s[k^1] = y;tr[y].fa = x;tr[z].s[w] = x;tr[x].fa = z;update(y);update(x);
}void Splay(int x, int to)
{while(tr[x].fa != to){int y = tr[x].fa, z = tr[y].fa;if(z == to){Rotate(x);break;}Rotate((tr[y].s[0] == x) ^ (tr[z].s[0] == y)? x: y); Rotate(x);}if(!to)root = x;
}int Find(int x)
{int now = root;while(1){int ls = tr[now].s[0], rs = tr[now].s[1], sum = tr[ls].siz + tr[now].r - tr[now].l + 1;if(x > tr[ls].siz && x <= sum){x -= tr[ls].siz;break;}if(x <= tr[ls].siz)     now = ls;else     x -= sum, now = rs;}return tr[now].l + x - 1;
}void Split(int x, int val)
{int ls, rs, L = tr[x].l, R = tr[x].r;if(L == R)return ;if(L == val){rs = ++tot;mp[R] = rs;mp[val] = x;tr[rs].s[1] = tr[x].s[1];tr[tr[rs].s[1]].fa = rs;tr[x].s[1] = rs;tr[rs].fa = x;tr[rs].l = L + 1;tr[rs].r = R;tr[x].r = L;update(rs);update(x);}else if(R == val){ls = ++tot;mp[R - 1] = ls;mp[val] = x;tr[ls].s[0] = tr[x].s[0];tr[tr[x].s[0]].fa = ls;tr[x].s[0] = ls;tr[ls].fa = x;tr[ls].l = L;tr[ls].r = R - 1;tr[x].l = R;update(ls);update(x);}else{ls = ++tot; rs = ++tot;    mp[val] = x;mp[val-1] = ls;mp[R] = rs;tr[ls].s[0] = tr[x].s[0];tr[rs].s[1] = tr[x].s[1];tr[tr[x].s[0]].fa = ls;tr[tr[x].s[1]].fa = rs;tr[x].s[0] = ls;tr[x].s[1] = rs;tr[x].l = tr[x].r = val;tr[ls].fa = tr[rs].fa = x;tr[ls].l = L;tr[ls].r = val - 1;tr[rs].l = val + 1;tr[rs].r = R;update(ls);update(rs);update(x);}Splay(x, 0);
}int Query(int x)
{Splay(x, 0);return tr[x].siz - tr[tr[x].s[1]].siz;
}
int timer;
void Del(int x)
{int pre = tr[x].s[0], las = tr[x].s[1];while(tr[pre].s[1])    pre = tr[pre].s[1];while(tr[las].s[0])    las = tr[las].s[0];if(!pre && !las)    root = 0;else if(!pre){Splay(las, root);root = las;tr[root].fa = 0;tr[0].s[1] = root;tr[x].s[0] = tr[x].s[1] = 0;tr[x].siz = 1;}else if(!las){Splay(pre, root);root = pre;tr[root].fa = 0;tr[0].s[1] = root;tr[x].s[0] = tr[x].s[1] = 0;tr[x].siz = 1;}else {Splay(pre, 0);Splay(las, root);tr[las].s[0] = tr[x].fa = 0;tr[x].siz = 1;update(las);update(pre);}
}void Insert_front(int x)
{if(!root){root = x;return ;}int lef = root;while(tr[lef].s[0])    lef = tr[lef].s[0];Splay(lef, 0);tr[root].s[0] = x;tr[x].fa = root;update(root);
}void Insert_back(int x)
{if(!root){root = x;return ;}int rig = root;while(tr[rig].s[1])rig = tr[rig].s[1];Splay(rig, 0);tr[root].s[1] = x;tr[x].fa = root;update(x);update(root);
}int main()
{read(n);read(m);mp[n] = root = Newnode(1, n, 0);tr[0].s[1] = root;for(int i = 1; i <= m; ++i){timer ++;int opt, x, y;read(opt);read(x);if(opt == 1){read(y);x -= res;y -= res;int z = mp.lower_bound(x) -> second;Split(z, x);res = Query(z);tr[z].l = tr[z].r = y;mp[y] = z;}else if(opt == 2){x -= res;int y = mp.lower_bound(x) -> second;Split(y, x);res = Query(y);Del(y);Insert_front(y);}else if(opt == 3){x -= res;int y = mp.lower_bound(x) -> second;Split(y, x);res = Query(y);Del(y);Insert_back(y);}else{x -= res;res = Find(x);}printf("%d\n", res);}return 0;
}
View Code

 

转载于:https://www.cnblogs.com/Joker-Yza/p/11230088.html

这篇关于[SCOI2014]方伯伯的OJ——Splay的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/560753

相关文章

哈理工OJ 2179(深搜)

组合 Time Limit: 1000 MSMemory Limit: 32768 K Total Submit: 7(5 users)Total Accepted: 6(5 users)Rating: Special Judge: No Description 给出一个正整数N,从集合{1,2,3..N} 中找出所有大小为k的子集, 并按照字典序从小到大输出。 Input 第一行是一个整

每日OJ_牛客_求和(递归深搜)

目录 牛客_求和(递归深搜) 解析代码 牛客_求和(递归深搜) 求和_好未来笔试题_牛客网 解析代码         递归中每次累加一个新的数,如果累加和大于等于目标,结束递归。此时如果累加和正好等于目标,则打印组合。向上回退搜索其它组合。此题本身就是一个搜索的过程,找到所有的组合。 #include <iostream>#include <cmath>#in

OJ-0905

题目 示例1: 输入:10 10 56 34 99 1 87 8 99 3 255 6 99 5 255 4 99 7 255 2 99 9 255 213 4输出:99 示例2: 输入:10 10 255 34 0 1 255 8 0 3 255 6 0 5 255 4 0 7 255 2 0 9 255 213 5输出:255 import java.util.

每日OJ_牛客_Emacs计算器(逆波兰表达式)

目录 牛客_Emacs计算器(逆波兰表达式) 解析代码 牛客_Emacs计算器(逆波兰表达式) Emacs计算器__牛客网 解析代码 逆波兰表达式(后缀表达式)求值,需要借助栈,思路: 循环输入,获取逆波兰表达式,然后进行以下补助,直到测试完所有的测试用例: 遇到数字字符串,将该数字字符串转化为数字然后入栈。遇到操作符时,从栈顶取两个数字,然后进行该运算符所对应运算

Splay树(区间更新)—— POJ 3468 A Simple Problem with Integers

对应POJ 题目:点击打开链接 A Simple Problem with Integers Time Limit: 5000MS Memory Limit: 131072KTotal Submissions: 72765 Accepted: 22465Case Time Limit: 2000MS Description You have N integers, A1

Splay树(区间添加删除 | 区间翻转)——HDU 3487 Play with Chain

对应HDU题目:点击打开链接 Play with Chain Time Limit: 6000/2000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 4571    Accepted Submission(s): 1859 Problem Descript

西北工业大学oj题-兔子生崽

题目描述: 兔子生崽问题。假设一对小兔的成熟期是一个月,即一个月可长成成兔,每对成兔每个月可以生一对小兔,一对新生的小兔从第二个月起就开始生兔子,试问从一对兔子开始繁殖,一年以后可有多少对兔子? 这道题目一眼看过去就是典型的递归问题,代码如下 public class RabbitReproduction {public static void main(String[] args) {in

★ 算法OJ题 ★ 力扣209 - 长度最小的子数组

Ciallo~(∠・ω< )⌒☆ ~ 今天,简将和大家一起做一道滑动窗口算法题--长度最小的子数组~ 目录 一  题目 二  算法解析 解法⼀:暴力求解 解法二:滑动窗口 三  编写算法 一  题目 209. 长度最小的子数组 - 力扣(LeetCode) 二  算法解析 解法⼀:暴力求解 算法思路: 从前往后枚举数组中的任意⼀个元素,把它当成起始位置

OJ-0903

题目 示例1 输入:30 12 25 8 19输出:15 示例2 输入:10 12 25 8 19 8 6 4 17 19 20 30输出:-1 题解 import java.util.ArrayList;import java.util.List;import java.util.Scanner;public class Main {public static

【负载均衡式在线OJ】Compile_server 模块

文章目录 程序源码compile_server整体思路编译(compile.hpp)运行模块编译运行模块编译运行服务 程序源码 https://gitee.com/not-a-stupid-child/online-judge compile_server 整体思路 这个服务要对oj_server 发送过来的代码进行编译和运行,最后把结果返回给oj_server。 所以我