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< ...
随机推荐
- bzoj1912
由于k只有2,所以我们分类讨论显然当k=1时,我们只要连一条最长的路径即可就是树的直径L少走了L-1条边如果k=2时,我们再次连边成环后如果成环路径与上一次的最长路径没有相同的边,那少走的边数是路径长 ...
- 裸机编程与OS环境编程的有关思考
这里的所谓的裸机编程指的是为“无OS支持的硬件系统编程”,而实际的编程工作肯定需要一个环境,通常这样的情况中,编程和编译的环境叫做“宿主机”,最终的程序在“目标机”上运行(交叉编译).而OS环境编程指 ...
- 高性能I/O设计模式Reactor和Proactor
系统I/O 可分为阻塞型, 非阻塞同步型,非阻塞异步型. (Linux对aio支持的不完整,所以linux上用Reactor比较多:Proactor需要系统API支持真正的“异步”) 阻塞型I/O意味 ...
- 《University Calculus》-chape10-向量与空间几何学-向量夹角
点积.向量夹角: 无论对于空间向量还是平面向量,我们所熟知的是:给出任意两个向量,我们都能够根据公式计算它们的夹角,但是这个夹角必须是将两个向量的起点重合后所夹成的小于等于π的角,可是,这是为什么呢? ...
- hdu4281 区间dp
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4283 #include<iostream> #include<algorithm&g ...
- Django中的Form
Form 一.使用Form Django中的Form使用时一般有两种功能: 1.生成html标签 2.验证输入内容 要想使用django提供的form,要在views里导入form模块 from dj ...
- 【设计模式 - 11】之享元模式(FlyWeight)
1 模式简介 当系统中存在大量对象时,非常容易造成内存溢出.为了解决这个问题,我们把这些对象中共有的部分抽象出来,如果有相同的业务请求,则直接返回在内存中已有的对象,避免重新创建,这就是享元 ...
- hadoop实例
一篇讲得很好的hadoop实例,非常适合初学者学习hadoop. 本文转载自:http://www.cnblogs.com/xia520pi/archive/2012/06/04/2534533.ht ...
- BAE、SAE 与 GAE 对比
从数据库.应用配置.计费.域名绑定.平台服务对比了 BAE.SAE 以及 GAE 的优劣,最后给出云平台选型的建议. 数据库SAE 不支持 InnoDB(可申请支持),BAE 默认支持. BAE 不支 ...
- POJ 1001 Exponentiation 无限大数的指数乘法 题解
POJ做的非常好,本题就是要求一个无限位大的指数乘法结果. 要求基础:无限大数位相乘 额外要求:处理特殊情况的能力 -- 关键是考这个能力了. 所以本题的用例特别重要,再聪明的人也会疏忽某些用例的. ...