终于把区间操作的Splay搞明白了……

Splay的大致框架是这样的:

【代码中的Zig-Zig和Zig-Zag操作其实是可以优化的,实际只需要3次passDown和3次update】

 template <class T>
 struct SplayNode
 {
     typedef SplayNode<T> Node;
     Node* lch;
     Node* rch;
     Node* parent;
     T val;

     SplayNode(const T& _val,Node* _parent):
             lch(),rch(),parent(_parent),val(_val) {}

     void passDown() {}
     void update() {}

     void lRotate()
     {
         if(parent->parent)
         {
             if(parent==parent->parent->lch)
                 parent->parent->lch=this;
             else parent->parent->rch=this;
         }

         parent->passDown();
         passDown();

         parent->rch=this->lch;
         if(lch) lch->parent=this->parent;

         lch=parent;
         parent=parent->parent;
         lch->parent=this;

         lch->update();
         update();
     }

     void rRotate()
     {
         if(parent->parent)
         {
             if(parent==parent->parent->lch)
                 parent->parent->lch=this;
             else parent->parent->rch=this;
         }

         parent->passDown();
         passDown();

         parent->lch=this->rch;
         if(rch) rch->parent=this->parent;

         rch=parent;
         parent=parent->parent;
         rch->parent=this;

         rch->update();
         update();
     }

     Node* splay()
     {
         while(parent)
         {
             ;
             ; ;
             if(parent->parent)
             {
                 ;
                 ;
             }

             switch(status)
             {
             :  rRotate(); break;
             :  lRotate(); break;
             :  parent->rRotate(); this->rRotate(); break;
             :  lRotate(); rRotate(); break;
             :  rRotate(); lRotate(); break;
             : parent->lRotate(); this->lRotate(); break;
             }
         }
         return this;
     }
 };

注意双旋的Zig-Zig(Zag-Zag)和Zig-Zag(Zag-Zig),后者可以分解成两次单旋,而前者不能。

借教室一题的85分代码(Vijos):

(Splay果然常数大……当然很可能是我写萎了……)

 #include <algorithm>

 using std::max;
 using std::min;

 struct SplayNode
 {
     typedef SplayNode Node;
     Node* lch;
     Node* rch;
     Node* parent;

     int idx;
     int val;
     int minVal;
     int lazyTag;

     SplayNode() {}

     SplayNode(int _idx,int _val,Node* _parent):
             lch(),rch(),parent(_parent),idx(_idx),val(_val),
             minVal(_val),lazyTag() {}

     void assign(int _idx,int _val,int _minVal,Node* _rch,Node* _parent)
     {
         idx=_idx;
         val=_val;
         minVal=_minVal;
         lazyTag=;
         lch=;
         rch=_rch;
         parent=_parent;
     }

     int actual() { return minVal + lazyTag; }

     void passDown()
     {
         if(!lazyTag) return;

         if(lch) lch->lazyTag += this->lazyTag;
         if(rch) rch->lazyTag += this->lazyTag;

         val += lazyTag;
         minVal += lazyTag;
         lazyTag = ;
     }

     void update()
     {
         minVal = lch ?
             ( rch ? min(min(lch->actual(),rch->actual()),this->val) :
                     min(lch->actual(),this->val) ) :
             ( rch ? min(rch->actual(),this->val) : this->val );
     }

     void lRotate()
     {
         if(parent->parent)
         {
             if(parent==parent->parent->lch)
                 parent->parent->lch=this;
             else parent->parent->rch=this;
         }

         parent->passDown();
         passDown();

         parent->rch=this->lch;
         if(lch) lch->parent=this->parent;

         lch=parent;
         parent=parent->parent;
         lch->parent=this;

         lch->update();
         update();
     }

     void rRotate()
     {
         if(parent->parent)
         {
             if(parent==parent->parent->lch)
                 parent->parent->lch=this;
             else parent->parent->rch=this;
         }

         parent->passDown();
         passDown();

         parent->lch=this->rch;
         if(rch) rch->parent=this->parent;

         rch=parent;
         parent=parent->parent;
         rch->parent=this;

         rch->update();
         update();
     }

     Node* splay()
     {
         while(parent)
         {
             ;
             ; ;
             if(parent->parent)
             {
                 ;
                 ;
             }

             switch(status)
             {
             :  rRotate(); break;
             :  lRotate(); break;
             :  parent->rRotate(); this->rRotate(); break;
             :  lRotate(); rRotate(); break;
             :  rRotate(); lRotate(); break;
             : parent->lRotate(); this->lRotate(); break;
             }
         }
         return this;
     }
 };

 ;

 SplayNode node[maxN];
 int n,m;

 int change(int d,int s,int t)
 {
     ;
     ) status |= ;
     ;

     switch(status)
     {
     :
         node[s-].splay();
         node[s-].rch->parent=;
         node[t+].splay();
         node[s-].rch=&node[t+];
         node[t+].parent=&node[s-];

         node[t+].lch->lazyTag -= d;
         node[t+].update();
         node[s-].update();
         ;
     :
         node[t+].splay();
         node[t+].lch->lazyTag -= d;
         node[t+].update();
         ;
     :
         node[s-].splay();
         node[s-].rch->lazyTag -= d;
         node[s-].update();
         ;
     :
         node[].splay();
         node[].val -= d;
         node[].minVal -= d;
         ].rch) node[].rch->lazyTag -= d;
         ;
     }
 }

 #include <cstdarg>
 #include <cstdio>
 #include <cctype>

 void readInt(int argCnt,...)
 {
     va_list va;
     va_start(va,argCnt);

     while(argCnt--)
     {
         int* dest=va_arg(va,int*);
         ;
         char curDigit;

         do curDigit=getchar(); while(!isdigit(curDigit));
         while(isdigit(curDigit))
         {
             destVal = destVal *  + curDigit - ';
             curDigit=getchar();
         }
         *dest=destVal;
     }

     va_end(va);
 }

 int avai[maxN];

 int main()
 {
     readInt(,&n,&m);

     ;i<=n;++i) readInt(,avai+i);

     for(int i=n;i;--i)
     {
         ,&node[i-]);
         ) node[i].assign(n,avai[i],min(avai[i],node[i+].minVal),&node[i+],);
         ].minVal),&node[i+],&node[i-]);
     }

     ;i<=m;i++)
     {
         int d,s,t;
         readInt(,&d,&s,&t);
         int rt=change(d,s,t);
         )
         {
             printf("-1\n%d",i);
             ;
         }
     }
     printf(");
     ;
 }

修正了一点失误+改成了静态内存

(也许出题人没想到有人会用splay写这道题,所以之前的错误居然没被查出来……)

对于这道题,我们需要给每个Node额外设立3个域:idx(教室的标号,作为键值),minVal(子树中val的最小值),和lazyTag(修改的懒惰标记)

对区间[L,R]进行修改时,首先将L-1提到根,然后将R+1提到根的右孩子处,那么R+1的左孩子就是待修改的区间

当然要特判L==1和R==n(即左/右端为边界的情况)

注意旋转过程中要不断下传lazyTag并对节点的minVal值更新

(这个超级麻烦,一定要把每个细节都想全了,稍有一点疏忽就会出错,而且很不好查)

询问时直接询问根节点的minVal值即可(注意要让根节点的lazyTag传下去)

NOIP2012 借教室 Splay初探的更多相关文章

  1. NOIP2012借教室[线段树|离线 差分 二分答案]

    题目描述 在大学期间,经常需要租借教室.大到院系举办活动,小到学习小组自习讨论,都需要 向学校申请借教室.教室的大小功能不同,借教室人的身份不同,借教室的手续也不一样. 面对海量租借教室的信息,我们自 ...

  2. NC16564 [NOIP2012]借教室

    NC16564 [NOIP2012]借教室 题目 题目描述 ​ 在大学期间,经常需要租借教室.大到院系举办活动,小到学习小组自习讨论,都需要向学校申请借教室.教室的大小功能不同,借教室人的身份不同,借 ...

  3. NOIP2012 借教室

    描述 在大学期间,经常需要租借教室.大到院系举办活动,小到学习小组自习讨论,都需要向学校申请借教室.教室的大小功能不同,借教室人的身份不同,借教室的手续也不一样.面对海量租借教室的信息,我们自然希望编 ...

  4. NOIP2012借教室

    题目描述 Description 在大学期间,经常需要租借教室.大到院系举办活动,小到学习小组自习讨论,都需要 向学校申请借教室.教室的大小功能不同,借教室人的身份不同,借教室的手续也不一样. 面对海 ...

  5. 【洛谷P1083】[NOIP2012]借教室

    借教室 [题目描述] 在n天中每天有一个可以借出的教室数,有m个订单,每个订单从第l天到第r天要借用x个教室.问能否满足所有的订单,若不能,输出第一个不能满足的订单编号. 思路: 1.1 ≤ n,m ...

  6. [NOIP2012]借教室 题解

    题目大意: 有一个n个数的数列,m个操作,第i个操作使[li,ri]区间建di,问第几个操作使数列中出现负数. 思路: 暴力显然过不了,那么就可以优化了,不难想到线段树,显然需要良好的姿势,那么就差分 ...

  7. luogu1083 [NOIp2012]借教室 (二分答案+差分)

    先二分一个答案x,然后通过差分来看有没有不满足的 #include<bits/stdc++.h> #define pa pair<int,int> #define lowb(x ...

  8. NOIP2012 借教室 题解 洛谷P1083

    一看就是暴力 好吧,其实是线段树或差分+二分,这里用的是差分+二分的做法. 二分部分的代码,套个二分板子就行 ,right=m; while(left<right)//二分 { ; ; else ...

  9. 洛谷 1083 (NOIp2012) 借教室——标记永久化线段树 / 差分+二分

    题目:https://www.luogu.org/problemnew/show/P1083 听说线段树不标记永久化会T一个点. 注意mn记录的是本层以下.带上标记的min! #include< ...

随机推荐

  1. bzoj2653

    CLJ神牛的可持久化论文的题目,果然厉害其实第一步能想到后面就还是很简单的首先是二分答案,转化为判定性问题然后对于区间内的数,比他大的标为1,小的标为-1显然,如果存在一个左右端点符合的区间使得这个区 ...

  2. 我的第一份vim程序

    vim太好用了吧!!!根本停不下来啊! devc++再见! /*==================================================================== ...

  3. UVa 10294 Arif in Dhaka (First Love Part 2)(置换)

    题目链接:http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=35397 [思路] Polya定理. 旋转:循环节为gcd(i,n) ...

  4. Delegate。。

    Delegate类简介------------------------ 命名空间:System程序集:mscorlib(在 mscorlib.dll 中) 委托(Delegate)类是一种数据结构,通 ...

  5. hdu 2546 典型01背包

    分析:每种菜仅仅可以购买一次,但是低于5元不可消费,求剩余金额的最小值问题..其实也就是最接近5元(>=5)时, 购买还没有买过的蔡中最大值问题,当然还有一些临界情况 1.当余额充足时,可以随意 ...

  6. Google视频搜索

    本博文的主要内容有 .Google视频搜索的介绍    .Google视频搜索之一:普通搜索    .Google视频搜索之二:高级搜索 1.Google视频搜索的介绍 https://zh.wiki ...

  7. bzoj4447 SCOI2015 小凸解密码 password

    传送门:bzoj4447 题解: 调试简直恶心,不过调完发现其实还是挺好写的. 用\(\mathrm{set}\)维护一段\(0\)区间的左右端点,每次最多修改两个点,所以很好维护. 查询的时候在\( ...

  8. JAVA 线程状态以及synchronized,wait,sleep,yield,notify,notifyAll

    java线程存在以下几种状态: 1: 创建状态(New):线程被new出来,还未调用start 2: 就绪状态(Runnable):又称为可执行状态,调用线程的start方法后,线程处于就绪状态,,线 ...

  9. sql 视图 按where条件多个字段取一个 分类: SQL Server 2014-12-01 14:09 308人阅读 评论(0) 收藏

    首先介绍一下 Case ..When...Then..End  的用法: CASEJiXiaoFind_RowID  WHEN '1' THENJiXiao_Money1  WHEN '2' THEN ...

  10. 文件上传~Uploadify上传控件~续(多文件上传)

    对于Uploadify文件上传之前已经讲过一次(文件上传~Uploadify上传控件),只不过没有涉及到多文件的上传,这回主要说一下多个文件的上传,首先,我们要清楚一个概念,多文件上传前端Upload ...