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< ...
随机推荐
- 数据库连接&数据库进程&数据库操作
root@webwall:/home/xiachengjiao# vi/webwall/mysql/my.cnf(看配置文件中的参数) root@webwall:/webwall/mysql/bin# ...
- 【转】Unity 相关经典博客资源总结(持续更新)
原文:http://blog.csdn.net/prothi/article/details/20123319 就作为一个记录吧,把平时看过的Unity相关的一些好的Blog记录并分享. 好的论坛: ...
- HDU 3045 Picnic Cows(斜率优化DP)
Picnic Cows Time Limit: 8000/4000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) Tota ...
- div样式调整小结 转载
1.多个div使用会自动换行,应该使用float属性 left : 对象浮在左边 right : 对象浮在右边 例如: float: left 和 float: right 是两个div左右排 ...
- 从奥鹏一个答案提取页面 看jquery知识点
http://oldlearn.open.com.cn/OEMSExercise/HomeworkReview.aspx?HomeworkId=9c034488-0a3d-4b9d-a6cc-e42 ...
- C# 模拟用户登录
, data.Length); newStream.Close(); request.CookieContainer ...
- OC封装的TLV数据格式解析库
作者:朱克锋 邮箱:zhukefeng@iboxpay.com 转载请注明出处:http://blog.csdn.net/linux_zkf TLV是一种可变格式,意思就是: Type类型, Leng ...
- winform 五子棋 判断输赢 分类: WinForm 2014-08-07 20:55 256人阅读 评论(0) 收藏
新手上路,高手勿进! 利用数组,根据新旧数组值的不同,获取那个点是什么棋子: 说明: 棋盘:15*15; 定义4个全局变量: string[,] stroldlist = new string[15, ...
- [RxJS] Utility operator: do
We just saw map which is a transformation operator. There are a couple of categories of operators, s ...
- [Flux] 2. Overview and Dispatchers
Flux has four major components: Stores, Dispatchers, Views, and Actions. These components interact l ...