NOIP2012 借教室 Splay初探
终于把区间操作的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初探的更多相关文章
- NOIP2012借教室[线段树|离线 差分 二分答案]
题目描述 在大学期间,经常需要租借教室.大到院系举办活动,小到学习小组自习讨论,都需要 向学校申请借教室.教室的大小功能不同,借教室人的身份不同,借教室的手续也不一样. 面对海量租借教室的信息,我们自 ...
- NC16564 [NOIP2012]借教室
NC16564 [NOIP2012]借教室 题目 题目描述 在大学期间,经常需要租借教室.大到院系举办活动,小到学习小组自习讨论,都需要向学校申请借教室.教室的大小功能不同,借教室人的身份不同,借 ...
- NOIP2012 借教室
描述 在大学期间,经常需要租借教室.大到院系举办活动,小到学习小组自习讨论,都需要向学校申请借教室.教室的大小功能不同,借教室人的身份不同,借教室的手续也不一样.面对海量租借教室的信息,我们自然希望编 ...
- NOIP2012借教室
题目描述 Description 在大学期间,经常需要租借教室.大到院系举办活动,小到学习小组自习讨论,都需要 向学校申请借教室.教室的大小功能不同,借教室人的身份不同,借教室的手续也不一样. 面对海 ...
- 【洛谷P1083】[NOIP2012]借教室
借教室 [题目描述] 在n天中每天有一个可以借出的教室数,有m个订单,每个订单从第l天到第r天要借用x个教室.问能否满足所有的订单,若不能,输出第一个不能满足的订单编号. 思路: 1.1 ≤ n,m ...
- [NOIP2012]借教室 题解
题目大意: 有一个n个数的数列,m个操作,第i个操作使[li,ri]区间建di,问第几个操作使数列中出现负数. 思路: 暴力显然过不了,那么就可以优化了,不难想到线段树,显然需要良好的姿势,那么就差分 ...
- luogu1083 [NOIp2012]借教室 (二分答案+差分)
先二分一个答案x,然后通过差分来看有没有不满足的 #include<bits/stdc++.h> #define pa pair<int,int> #define lowb(x ...
- NOIP2012 借教室 题解 洛谷P1083
一看就是暴力 好吧,其实是线段树或差分+二分,这里用的是差分+二分的做法. 二分部分的代码,套个二分板子就行 ,right=m; while(left<right)//二分 { ; ; else ...
- 洛谷 1083 (NOIp2012) 借教室——标记永久化线段树 / 差分+二分
题目:https://www.luogu.org/problemnew/show/P1083 听说线段树不标记永久化会T一个点. 注意mn记录的是本层以下.带上标记的min! #include< ...
随机推荐
- 【转】实现展开列ExpandableListView的三种方式之SimpleExpandableListAdapter实例
原文网址:http://blog.csdn.net/x605940745/article/details/12099709 实现可扩展展开列ExpandableListView的三种方式 欢迎加入QQ ...
- (转载)PHP json_encode() 函数介绍
(转载) 在 php 中使用 json_encode() 内置函数(php > 5.2)可以使用得 php 中数据可以与其它语言很好的传递并且使用它. 这个函数的功能是将数值转换成json数据存 ...
- 性能指标--并发用户数(Concurrent Users)
并发用户数是指:在某一时间点,与被测目标系统同时进行交互的客户端用户的数量. 并发用户数有以下几种含义: 1. 并发虚拟用户数(Concurrent Virtual Users,Users_CVU) ...
- 用Delphi制作仿每行带按钮的列表
Delphi做程序开发在使用到列表控件时,一般是列表放文本内容,在列表以外放操作按钮,选中列表某项再点按钮进行操作.现在Web开发做列表的样式总是列表的每行都有操作按钮,如微博的列表风格: Web开发 ...
- 邮件发送小demo
//send email public static bool SendEmail() { //实例化发件人地址 MailAddress from = new MailAddress("aa ...
- Hdu 4010-Query on The Trees LCT,动态树
Query on The Trees Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 65768/65768 K (Java/Othe ...
- [ReadingNotes] Search the links, static final in the java
[ReadingNotes] Search the links, static final in the java */--> pre { background-color: #2f4f4f;l ...
- php写excel
$this->loadexcel(); $objPHPExcel = new PHPExcel(); $objPHPExcel->getProperties() ...
- VShell破解版
VShell破解版 VShell破解版
- Java内部类的一些总结
作为刚入门Java的小白,这两天看到内部类,这里做一个总结,若有错误,欢迎指正~ 内部类是指在一个外部类的内部再定义一个类.类名不需要和文件夹相同. 内部类分为: 成员内部类.局部内部类.静态嵌套类. ...