链接:https://codeforces.com/problemset/problem/675/D

题意:

给一个二叉搜索树,一开始为空,不断插入数字,每次插入之后,询问他的父亲节点的权值

题解:

由二叉搜索树的有序性质,

他的父亲节点一定是和他向上和向下最接近的两个中,最后插入的那一个

那么我们对于每一个数字标记其插入的时间,然后维护一棵平衡二叉树用于插值和查找用即可

主要是记录一下我的伸展树代码

据说指针比数组快,但是我这里不仅数组比指针快,甚至用vector和用数组的速度也是一样的

指针:

数组:

1.指针版

  1. #include <bits/stdc++.h>
  2. #define endl '\n'
  3. #define ll long long
  4. #define IO ios::sync_with_stdio(false);cin.tie(0);cout.tie(0)
  5. using namespace std;
  6. const int maxn=1e6+10,maxm=2e6+10;
  7. const int INF=0x3f3f3f3f;
  8. const int mod=1e9+7;
  9. const double PI=acos(-1.0);
  10. //head
  11. int casn,n,m,k;
  12. int num[maxn];
  13. class splaytree{
  14. public:
  15. struct splaynode{
  16. splaynode *son[2],*pre;
  17. ll val;
  18. splaynode(int x=0,splaynode *fa=NULL){
  19. pre=fa;
  20. son[0]=son[1]=NULL;
  21. val=x;
  22. }
  23. };
  24. typedef struct splaynode* nodep;
  25. int cnt;
  26. nodep root;
  27. vector<splaynode> node;
  28. void rotate(nodep now,int d){
  29. nodep fa=now->pre;
  30. fa->son[!d]=now->son[d];
  31. if(now->son[d]) now->son[d]->pre=fa;
  32. now->pre=fa->pre;
  33. if(fa->pre){
  34. if(fa->pre->son[0]==fa) fa->pre->son[0]=now;
  35. else fa->pre->son[1]=now;
  36. }else root=now;
  37. now->son[d]=fa;
  38. fa->pre=now;
  39. }
  40. void splay(nodep now,nodep dst){
  41. while(now->pre!=dst){
  42. if(now->pre->pre==dst)rotate(now,now->pre->son[0]==now);
  43. else{
  44. nodep fa=now->pre;
  45. int d=(fa->pre->son[0]==fa);
  46. if(fa->son[d]==now){
  47. rotate(now,!d);
  48. rotate(now,d);
  49. }else {
  50. rotate(fa,d);
  51. rotate(now,d);
  52. }
  53. }
  54. }
  55. if(!dst) root=now;
  56. }
  57. int insert(int val){
  58. if(!root) {
  59. node[cnt]=splaynode(val);
  60. root=&node[cnt++];
  61. return 0;
  62. }
  63. nodep now=root;
  64. int flag=(now->val)<val;
  65. while(now->son[flag]){
  66. if((now->val)==val){
  67. splay(now,NULL);
  68. return 0;
  69. }
  70. now=now->son[flag];
  71. flag=((now->val)<val);
  72. }
  73. node[cnt]=splaynode(val,now);
  74. now->son[flag]=&node[cnt++];
  75. splay(now->son[flag],NULL);
  76. return 1;
  77. }
  78. int bound(int d){
  79. nodep now=root->son[d];
  80. if(!now) return INF;
  81. while(now->son[d^1]) now=now->son[d^1];
  82. return now->val;
  83. }
  84. splaytree(int n){
  85. cnt=0;
  86. node.resize(n+7);
  87. root=NULL;
  88. }
  89. };
  90. map<int,int> vis;
  91. int main() {
  92. IO;
  93. cin>>n;
  94. splaytree tree(n);
  95. while(n--){
  96. int a;
  97. cin>>a;
  98. vis[a]=maxn-n;
  99. if(!tree.insert(a)) continue;
  100. int mn=tree.bound(0);
  101. int mx=tree.bound(1);
  102. if(vis[mn]>vis[mx]) cout<<mn<<' ';
  103. else cout<<mx<<' ';
  104. }
  105. return 0;
  106. }

2.数组版

  1. #include <bits/stdc++.h>
  2. #define endl '\n'
  3. #define ll long long
  4. #define IO ios::sync_with_stdio(false);cin.tie(0);cout.tie(0)
  5. using namespace std;
  6. const int maxn=1e6+10,maxm=2e6+10;
  7. const int INF=0x3f3f3f3f;
  8. int casn,n,m,k;
  9. class splaytree{
  10. #define nd node[now]
  11. public:
  12. struct splaynode{
  13. int son[2],pre;
  14. ll val;
  15. splaynode(int x=0,int fa=0){
  16. pre=fa;
  17. son[0]=son[1]=0;
  18. val=x;
  19. }
  20. };
  21. int cnt;
  22. int root;
  23. vector<splaynode> node;
  24. void rotate(int now,int d){
  25. int fa=nd.pre;
  26. node[fa].son[!d]=nd.son[d];
  27. node[nd.son[d]].pre=fa;
  28. if(node[fa].pre){
  29. node[node[fa].pre].son[node[node[fa].pre].son[1]==fa]=now;
  30. }else root=now;
  31. nd.pre=node[fa].pre;
  32. nd.son[d]=fa;
  33. node[fa].pre=now;
  34. }
  35. void splay(int now,int dst){
  36. while(nd.pre!=dst){
  37. if(node[nd.pre].pre==dst)rotate(now,node[nd.pre].son[0]==now);
  38. else{
  39. int fa=nd.pre;
  40. int d=(node[node[fa].pre].son[0]==fa);
  41. if(node[fa].son[d]==now){
  42. rotate(now,!d);
  43. rotate(now,d);
  44. }else {
  45. rotate(fa,d);
  46. rotate(now,d);
  47. }
  48. }
  49. }
  50. if(!dst) root=now;
  51. }
  52. int insert(int val){
  53. if(!root) {
  54. node[cnt]=splaynode(val);
  55. root=cnt++;
  56. return 0;
  57. }
  58. int now=root;
  59. int flag=nd.val<val;
  60. while(nd.son[flag]){
  61. if(nd.val==val){
  62. splay(now,0);
  63. return 0;
  64. }
  65. now=nd.son[flag];
  66. flag=nd.val<val;
  67. }
  68. node[cnt]=splaynode(val,now);
  69. nd.son[flag]=cnt++;
  70. splay(nd.son[flag],0);
  71. return 1;
  72. }
  73. int bound(int d){
  74. int now=node[root].son[d];
  75. if(!now) return INF;
  76. while(nd.son[d^1]) now=nd.son[d^1];
  77. return nd.val;
  78. }
  79. splaytree(int n){
  80. cnt=1,root=0;
  81. node.resize(n+7);
  82. }
  83. };
  84. map<int,int> vis;
  85. int main() {
  86. IO;
  87. cin>>n;
  88. splaytree tree(n);
  89. while(n--){
  90. int a;
  91. cin>>a;
  92. vis[a]=maxn-n;
  93. if(!tree.insert(a)) continue;
  94. int mn=tree.bound(0);
  95. int mx=tree.bound(1);
  96. if(vis[mn]>vis[mx]) cout<<mn<<' ';
  97. else cout<<mx<<' ';
  98. }
  99. return 0;
  100. }

Codeforces 675D Tree Construction Splay伸展树的更多相关文章

  1. CodeForces 675D Tree Construction

    递归,$RMQ$. 因为$n$较大,可以采用递归建树的策略. 对每一个点标一个$id$.然后按照$v$从小到大排序,每一段$[L,R]$的根节点就是$id$最小的那个. 因为二叉搜索树可能是一条链,所 ...

  2. codeforces 675D Tree Construction set

    转自:http://blog.csdn.net/qwb492859377/article/details/51447350 #include <stdio.h> #include < ...

  3. Splay伸展树学习笔记

    Splay伸展树 有篇Splay入门必看文章 —— CSDN链接 经典引文 空间效率:O(n) 时间效率:O(log n)插入.查找.删除 创造者:Daniel Sleator 和 Robert Ta ...

  4. 【学时总结】◆学时·VI◆ SPLAY伸展树

    ◆学时·VI◆ SPLAY伸展树 平衡树之多,学之不尽也…… ◇算法概述 二叉排序树的一种,自动平衡,由 Tarjan 提出并实现.得名于特有的 Splay 操作. Splay操作:将节点u通过单旋. ...

  5. Splay 伸展树

    废话不说,有篇论文可供参考:杨思雨:<伸展树的基本操作与应用> Splay的好处可以快速分裂和合并. ===============================14.07.26更新== ...

  6. [Splay伸展树]splay树入门级教程

    首先声明,本教程的对象是完全没有接触过splay的OIer,大牛请右上角.. 首先引入一下splay的概念,他的中文名是伸展树,意思差不多就是可以随意翻转的二叉树 PS:百度百科中伸展树读作:BoGa ...

  7. Splay伸展树入门(单点操作,区间维护)附例题模板

    Pps:终于学会了伸展树的区间操作,做一个完整的总结,总结一下自己的伸展树的单点操作和区间维护,顺便给未来的自己总结复习用. splay是一种平衡树,[平均]操作复杂度O(nlogn).首先平衡树先是 ...

  8. [算法] 数据结构 splay(伸展树)解析

    前言 splay学了已经很久了,只不过一直没有总结,鸽了好久来写一篇总结. 先介绍 splay:亦称伸展树,为二叉搜索树的一种,部分操作能在 \(O( \log n)\) 内完成,如插入.查找.删除. ...

  9. CF 675D——Tree Construction——————【二叉搜索树、STL】

    D. Tree Construction time limit per test 2 seconds memory limit per test 256 megabytes input standar ...

随机推荐

  1. GET和POST传输方式

    GET和POST传输 在很多人看来,get和post的区别有比如安不安全,传输有大小限制等,在这里,我将对get和post做出客观的评价: GET: 传输方法:get传输数据一般是在地址栏的url的问 ...

  2. IO流--序列化流与反序列化流

    IO流--序列化流与反序列化流: 序列化流:把对象当做流一样写入到文本文件中 ObjectOutputSream(); 反序列化流:把文本文件中的流对象还原成对象ObjectInputSream(): ...

  3. while应用和函数学习

    # ******************************练习****************************# 在控制台中获取两个整数,作为循环开始和结束的点'''a = int(in ...

  4. [Android] Android读取Asset下文件的最简单的方法总结(用于MediaPlayer中)

    方法一:getAssets().openFd //读取asset内容    private void openAssetMusic(String index) throws IOException { ...

  5. 伪触发 input file 的click事件

    前端在做 input file 美化的时候,通常 把 input 定位position 到 已美化的按钮最上方 opacity: 0 HTML5时代,已有更方便的方法,点击美化按钮直接触发选择文件事件 ...

  6. SpringBoot 2.0集成spring-data-elasticsearch

    1 资料 https://segmentfault.com/a/1190000015568618 https://github.com/JeffLi1993/springboot-learning-e ...

  7. github下载更新代码到本地

    git remote -v git fetch origin master git log -p  master.. origin/master 如果本地已修改需要 git stash git mer ...

  8. SQL 编程技巧

    Ø  简介 本文主要介绍编写 SQL 时的一些编程技巧,方便有时候忘了便于查看,主要包含以下内容: 1.   SQL 语句中使用 +=.-=.*=./= 运算符 2.   值为 NULL 的列或局部变 ...

  9. zookeeper客户端 zkCli使用及常用命令

    上篇(http://www.cnblogs.com/yangzhenlong/p/8270835.html)zk伪集群搭建好后,使用zkCli连接zk服务 切换到zk1/bin 目录,执行zkCli. ...

  10. luogu P5112 FZOUTSY

    传送门 毒瘤出题人,卡我常数 如果后缀排序后将两两之间height\(\ge k\)的后缀放在一组,那么每次询问的答案就是\(\sum_{i} \binom{num[i]}{2}\)(num[i]是第 ...