进入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. WPF 多线程处理(2)

    WPF 多线程处理(1) WPF 多线程处理(2) WPF 多线程处理(3) WPF 多线程处理(4) WPF 多线程处理(5) WPF 多线程处理(6) WPF UI 设计需要自动适应窗体大小,那么 ...

  2. The Black Hole of Numbers (strtoint+inttostr+sort)

    For any 4-digit integer except the ones with all the digits being the same, if we sort the digits in ...

  3. Eclipse--Team--SVN--URL修改

    1.团队开发服务器,有的时候会更换地址 解决: eclipse--菜单Windows-Show View-others-svn--svn资源库 打开资源库面板 右击http://localhost:9 ...

  4. PHP - PDO 之 mysql 参数绑定

    <?php /* pdo 学习 */ $dsn = 'mysql:host=localhost;dbname=cswl';//构建连接dsn $db = new pdo($dsn,'root', ...

  5. 传统ASP.NET开发和MVC的设计思想

    传统ASP.NET开发 第一步:客户端请求服务器: 第二步:服务器从数据库取得数据处理后响应给客户端页面. MVC的设计思想 第一步:客户端请求控制器(里面的一个方法): 第二步:控制器从数据库里取得 ...

  6. 一步步学习NHibernate(9)——连接查询和子查询(1)

    请注明转载地址:http://www.cnblogs.com/arhat 在前几章中,我们把HQL的基本查询学习了一下,但是只有基本查询很显然不能满足我们的需求,那么就需要一下复杂查询比如" ...

  7. spring dataSourceRouter自动切换数据源

    spring多数据源的切换,主要用到的是AbstractRoutingDataSource这个路由类,当我们的自定义的一个路由分发类继承AbstractRoutingDataSource类后,重写de ...

  8. AirDrop显示名字的修改问题

    AirDrop的名字来源是设备登陆的iCloud账户 打开iCloud设置 把个人信息的名字改成自己的即可 前提是你的账号没有借朋友用过,如果朋友用过恰好没注销,你的通讯录又有你的朋友的号码,很有可能 ...

  9. LocalStorage 本地存储

    首先自然是检测浏览器是否支持本地存储.在HTML5中,本地存储是一个window的属性,包括localStorage和sessionStorage,从名字应该可以很清楚的辨认二者的区别,前者是一直存在 ...

  10. The7th Zhejiang Provincial Collegiate Programming Contest->Problem A:A - Who is Older?

    http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3322 可以看样例猜题意的水题. #include<bits/stdc ...