进入splay tree的学习中;

据说splay tree在理论上功能十分强大,好好学;

splay首先一定是一棵BST,所以记不得的时候画个图就明白;

首先总结一下splay基本的操作左旋,右旋;

设节点x,其父节点y

左旋:保留x的右子树,y的左子树,将y插入到x的x的左子树上并原来x的左子树接到y的右子树上,右旋反之;

而Splay(x,s) (将x伸展为s的孩子)要分三种情况:

若y是根节点,则x在哪儿往相反方向旋(左孩子右旋,右孩子左旋)

若y的父节点是z,则若三点一线,先旋y再旋x

否则一直旋x,在哪儿反向旋;具体画个图就知道了;

核心就是在哪儿反向旋(是左孩子右旋,右孩子左旋)

然后分析一下splay的几个操作;

插入:很简单,按着BST的做法既可,之后把插入的元素伸展到根节点

删除:分类讨论,若要删除的节点x无孩子,那么直接删除(这不废话吗);

若x有1个孩子,那么把孩子接到父节点y上,然后删除;

若x有2个孩子,那么,就有点麻烦了;

首先找到x的后继p(第一个比x大的数),用其代替x,而本来p的孩子(只可能是有孩子),接到p父节点的左子树上

找K大数,这个跟BST一样

这三道平衡树的题目中,1503比较有思维难度(毕竟是noi)

有两个问题比较难处理 1.怎么修改 2.怎么删除

删除比较好办,把limit插入到tree中,然后删去左子树即可(注意:这里相等的值要插入到左子树中,原因见后文)

UPD:实际上相等的值处理应该在对应节点记录下出现次数即可

修改难住了我,一开始想的是想线段树一样加一个lazy域,可觉得删除,伸展时还要维护实在太烦;

后经人点醒,才明白完全可以只用一个全局变量temp来维护,

temp表示整个序列(不只是当前,当然好像也不好表示当前……)都修改的值,于是

相应的新加入的值就变为x-temp

附代码:

 var lazy,a,fa,count:array[..] of longint;
    son:array[..,..] of longint;
    temp,m,n,lim,i,x,root,s:longint;
    c:char; procedure middle(i:longint);
  begin
    if son[i,]<> then middle(son[i,]);
    write(a[i]+temp,' ');
    if son[i,]<> then middle(son[i,]);
  end; procedure pushup(x:longint);       //一种很简便的维护子树方法,不需要记得这么烦
  begin
    count[x]:=count[son[x,]]+count[son[x,]]+;
  end; procedure rotate(x,f:longint);
  var y,p:longint;
  begin
    y:=fa[x];
    fa[x]:=fa[y];
    if fa[y]<> then
    begin
      if son[fa[y],]=y then son[fa[y],]:=x
      else son[fa[y],]:=x;
    end;
    son[y,-f]:=son[x,f];
    if son[x,f]<> then fa[son[x,f]]:=y;
    fa[y]:=x;
    son[x,f]:=y;
    pushup(y);             //注意顺序
    pushup(x);
  end; procedure splay(x:longint);
  var y:longint;
  begin
    while fa[x]<> do
    begin
      y:=fa[x];
      if fa[y]= then
      begin
        if son[y,]=x then
          rotate(x,)
        else rotate(x,);
      end
      else if son[fa[y],]=y then
      begin
        if son[y,]=x then
        begin
          rotate(y,);
          rotate(x,);
        end
        else begin
          rotate(x,);
          rotate(x,);
        end;
      end
      else if son[fa[y],]=y then
      begin
        if son[y,]=x then
        begin
          rotate(x,);
          rotate(x,);
        end
        else begin
          rotate(y,);
          rotate(x,);
        end;
      end;
    end;
    pushup(x);
    root:=x;
  end; procedure insert(x:longint);
  var p:longint;
  begin
    inc(m);
    son[m,]:=;
    son[m,]:=;
    count[m]:=;
    a[m]:=x;
    if root= then
    begin
      root:=m;
      fa[m]:=;
    end
    else begin
      p:=root;
      repeat
        inc(count[p]);
        if a[p]>=x then                 //注意:为什么要把等于的插入左子树,因为删除的时候删的是左子树,而如果比现在插入到右子树,根据之前的分析,将x旋转到根后,相等的父节点p会变成x的左子树(在哪就被旋转到相反到,相等时不需要删去)
        begin
          if son[p,]= then break;
          p:=son[p,];
        end
        else begin
          if son[p,]= then break;
          p:=son[p,];
        end;
      until false;
      fa[m]:=p;
      if a[p]>=x then son[p,]:=m else son[p,]:=m;
      splay(m);
    end;
  end; function kth(x:longint):longint;
  var p,h:longint;
  begin
    p:=root;
    h:=x;
    while h<>count[son[p,]]+ do
    begin
      if h>count[son[p,]]+ then
      begin
        h:=h-count[son[p,]]-;
        p:=son[p,];
      end
      else p:=son[p,];
    end;
    exit(p);
  end; begin
  readln(n,lim);
  temp:=;
  for i:= to n do
  begin
    readln(c,x);
    if c='I' then
    begin
      if x>=lim then
      begin
        insert(x-temp);
        s:=s+;
      end;
    end
    else if c='S' then
    begin
      temp:=temp-x;
      insert(lim-temp);
      if son[m,]<> then             
      begin
        root:=son[m,];
        fa[son[m,]]:=;
        m:=m-;
      end
      else begin
        root:=;
        fillchar(fa,sizeof(fa),);
        fillchar(count,sizeof(count),);
        fillchar(son,sizeof(son),);
        m:=;
      end;
    end
    else if c='A' then temp:=temp+x
    else if c='F' then
      if x>count[root] then writeln(-) else writeln(a[kth(x)]+temp);   //注意打印的时候不忘+temp
 // middle(root);
  end;
  writeln(s-count[root]);         //count[root]就代表了整棵树的规模,即现有的人数
end.

bzoj1503

另外附删除节点编号为x的子程序;

 function find(i,f:longint):longint;
  var p:longint;
  begin
    p:=son[i,f];
    while son[p,-f]<> do p:=son[p,-f];  //后缀:右孩子的最左节点
    find:=p;
  end; procedure delete(i:longint);
  var p,q:longint;
  begin
    dec(t);
    if t= then
    begin
      root:=;
      f:=-;
      exit;
    end;
    p:=;
    if son[fa[i],]=i then p:=
    else if son[fa[i],]=i then p:=;
    if (son[i,]<>) and (son[i,]<>) then
    begin
      q:=find(i,);
      if root=i then root:=q;
      if fa[q]<>i then      //当后继就是x的左孩子时,后继的孩子依然接在后继上
      begin
        son[fa[q],]:=son[q,];
        fa[son[q,]]:=fa[q];
      end;
      fa[q]:=fa[i];
      son[fa[i],p]:=q;
      son[q,]:=son[i,];
      fa[son[q,]]:=q;
      if son[i,]<>q then         //小细节
      begin
        son[q,]:=son[i,];
        fa[son[q,]]:=q;
      end;
      fa[i]:=-;
      son[i,]:=;
      son[i,]:=;
    end
    else begin
      q:=;
      if son[i,]<> then q:=;
      if son[i,]<> then q:=;
      if root=i then root:=son[i,q];
      if q= then son[fa[i],p]:=
      else begin
        fa[son[i,q]]:=fa[i];
        son[fa[i],p]:=son[i,q];
      end;
      fa[i]:=-;
    end;
  end;

UPD:这是比较糟糕的写法……

bzoj1588,1208,1503的更多相关文章

  1. BZOJ 1503: [NOI2004]郁闷的出纳员

    1503: [NOI2004]郁闷的出纳员 Time Limit: 5 Sec  Memory Limit: 64 MBSubmit: 10526  Solved: 3685[Submit][Stat ...

  2. hdu 1503 Advanced Fruits

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1503 思路:这是一道最长公共子序列的题目,当然还需要记录路径.把两个字符串的最长公共字串记录下来,在递 ...

  3. BZOJ 1208: [HNOI2004]宠物收养所

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

  4. 【bzoj1588】 HNOI2002—营业额统计

    http://www.lydsy.com/JudgeOnline/problem.php?id=1588 (题目链接) 题意 给出一个序列,对于每一个数,找出之前与它相差最小的数,两者相减取绝对值加入 ...

  5. CSU 1503 点到圆弧的距离(2014湖南省程序设计竞赛A题)

    题目链接:http://acm.csu.edu.cn/OnlineJudge/problem.php?id=1503 解题报告:分两种情况就可以了,第一种是那个点跟圆心的连线在那段扇形的圆弧范围内,这 ...

  6. HDU 1503 带回朔路径的最长公共子串

    http://acm.hdu.edu.cn/showproblem.php?pid=1503 这道题又WA了好几次 在裸最长公共子串基础上加了回溯功能,就是给三种状态各做一个 不同的标记.dp[n][ ...

  7. POJ 1503

    http://poj.org/problem?id=1503 对于这个题我也是醉了,因为最开始是有学长和我们说过这个题目的,我以为我记得题目是什么意思,也就没看题目,结果按案例去理解题意,结果WA了一 ...

  8. BZOJ 1503: [NOI2004]郁闷的出纳员 splay

    1503: [NOI2004]郁闷的出纳员 Description OIER公司是一家大型专业化软件公司,有着数以万计的员工.作为一名出纳员,我的任务之一便是统计每位员工的工资.这本来是一份不错的工作 ...

  9. csuoj 1503: 点到圆弧的距离

    http://acm.csu.edu.cn/OnlineJudge/problem.php?id=1503 1503: 点到圆弧的距离 时间限制: 1 Sec  内存限制: 128 MB  Speci ...

随机推荐

  1. Laravel框架数据库CURD操作、连贯操作总结

    这篇文章主要介绍了Laravel框架数据库CURD操作.连贯操作.链式操作总结,本文包含大量数据库操作常用方法,需要的朋友可以参考下 一.Selects 检索表中的所有行 复制代码代码如下: $use ...

  2. Mysql 存储过程小例子

    创建存储过程: DELIMITER $$ USE `database_name`$$ DROP PROCEDURE IF EXISTS `add_or_update_user`$$ )) BEGIN ...

  3. 用python实现了一下:甲乙两人互猜数字(数理逻辑)

    今天在园子里看到博客:超难面试题:甲乙两人互猜数字(数理逻辑).然后琢磨了半天,写了个Python程序实现算法,我得出来的结果是1,6或1,8或35,42的组合, 不知道是否正确,请高人指点? 下面列 ...

  4. SQL 跨服务器数据库增、删、改、查(二)

    --创建链接服务器 exec sp_addlinkedserver 'jx3xxiednr3ucidf', ' ', 'SQLOLEDB', 'jx3xxiednr3ucidf' exec sp_ad ...

  5. js获取当前浏览器页面高度及宽度信息的方法

    var scrollLeft = Math.max(document.documentElement.scrollLeft, document.body.scrollLeft); var scroll ...

  6. C#结合js 上传文件和删除文件(技术点有:asp.net mvc ,nhibernate,ajax等)

    之前做项目的时候要用到上传文件的功能,现在我总结一下,上传文件和删除文件的代码,在以后的使用的过程中也更方便查找. [HttpPost] public ActionResult EditUser() ...

  7. Elasticsearch从0.90(0.90.x)到1.2(1.x)API的变化-二

    本文为官方文档的译文加个人理解.作者翻译时,elasticsearch(下面简称es)的版本为1.2.2. 请支持原创:http://www.cnblogs.com/donlianli/p/38367 ...

  8. Elasticsearch从0.90到1.2的不兼容变化-系统和设置

      本文为官方文档的翻译加个人理解.作者翻译时,elasticsearch(下面简称es)的版本为1.2.1.   1.系统级别及设置方面 1.1 es启动时,默认是作为一个前台程序启动.如果你想让e ...

  9. 应该如何入门deep learning呢?从UFLDL开始!

    抱歉,大家,这里不是要分享如何学习deep learning,而是想要记录自己学习deep learning的小历程,算是给自己的一点小动力吧,希望各位业内前辈能够多多指教! 看到有网友提到,Andr ...

  10. ionicPopup弹出列表选择对话框

    //显示vm.selectWarehouse = function() { vm.popupForWarehouse = $ionicPopup.show({ template: '<div c ...