Portal --> broken qwq

Description

  (这个描述好像怎么都精简不起来啊qwq)

  大概是说你的计算机有1GB的物理内存,按照Byte寻址,其物理地址空间为\(0\sim 2^{30}-1\),然后要支持以下三种操作:

(1)alloc k:申请一段长度为\(k\) byte的内存,申请成功返回该段内存的标号。分配方式为将当前未分配的地址中最小的\(k\)个依次分给该内存段(可能不连续),如果当前内存少于\(k\) byte,执行失败

(2)free i:释放标号为\(i\)的内存段,该内存段中的物理内存状态被重置为未分配,如果说该标号不存在或者说已经被释放则执行失败

(3)access i,p:计算标号为\(i\)的内存段的第\(p\)个byte的物理地址,如果标号不合法或者位置不合法执行失败。\(p\)从\(0\)开始计算

  数据范围:多组数据,数据组数为\(T\),\(1<=n<=2*10^5,T<=5\)

  

Solution

  这题首先有一个难点就是你的语文一定要很好== alloc操作中,不管申请成功与否,都是先开了一个新的内存段的qwq,所以不管有没有成功标号都要加一

  然后我们就可以开始做题了qwq

  这题有两种做法,可以选择用非旋treap或者线段树,虽然说两个算法在实际运行的时候表现都十分优秀但是。。貌似前者的复杂度。。有点问题==(具体我也不是很清楚qwq这个时候应该疯狂膜拜lyy)

  接下来讲一下线段树的做法

  其实这题和某道splay板题有点像【Portal -->】,大体的思路也是我可以用一个点来表示一整个区间,然后只有在要用的时候再将这个点要用的部分给。。切出来就好了

  所以现在先确定一下我们要干的大概是什么:首先我们可以建一棵\(0\sim 2^{30}-1\)的线段树(初始的时候只是一个点,如果一定要建出来的话每个节点对应的区间长度应该是\(2\)的整数次幂),然后每次alloc我们从这棵线段树中切一部分出来分配到当前内存段下,每次free我们又将某段内存段对应的那一部分给接回大的线段树中,access就直接查找就好了

  所以我们需要实现的是:分离(split)、合并(merge)、查找(query)

  合并的话就是正常的线段树合并即可,没有什么特别的地方

  至于其他的操作,首先先定义一些要维护的值:

  为了方便表示区间,我们考虑给每个节点打上一个\(tag\),具体含义就是:如果说\(tag\)为\(-1\),那么说明这个节点的区间已经分裂出左儿子和右儿子了,具体的统计什么的要继续递归处理其左右儿子,否则表示这个区间还没有分裂出左儿子和右儿子,并且这个区间的长度是\(2^{tag}\)

  同时我们用\(sz\)表示每个节点表示的区间中实际有多少个空置的叶子节点

  至于如何将一个节点存的区间给建出来的话。。考虑实现一个pushdown,如果说当前节点还能分的话那么新建左右儿子,并且左右儿子的\(tag\)值应该是父亲的\(tag\)值\(-1\),这里注意一下我们需要区分不能继续往下分的节点和可以继续往下分但是当前没有分的节点(说白了就是两个目前都没有后继可是前者不可以继续往下递归),实现的时候可以一个的左右儿子都设为\(-1\),另一个都设为\(0\)

  

  然后我们讲分离操作

  假设我们要将前\(k\)个位置分离出来(其实也就是前\(k\)个叶子节点),我们其实相当于在线段树上面找到第\(k\)个位置,然后把沿路上所有”前面“的部分全部提出来,并且将这些部分与原来大的线段树的连边删掉,所以我们只要一路上经过的节点都复制一个出来(用来链接),然后如果说递归走到左儿子那么不需要进行操作,如果递归走到右儿子说明整个左子树都是应该被提出来的部分,所以左子树直接断开,\(k\)递归的时候处理就按照找第\(k\)小处理就好了,注意不管是哪种情况,当前节点的\(sz\)都要减去\(k\)(被切掉了)

  接着是查询操作

  查询的话,我们直接在查询的内存段对应的线段树里面找第\(k\)个位置(从\(0\)开始数),具体实现有点玄学,因为我们要求这个位置原本的物理地址,也就是这个在原来大的线段树中是第几个叶子节点,所以考虑维护一个\(ret\)值,表示递归到当前这层,在前面的有多少个区间(这样说有点抽象,看图):

  然后如果说我们在查找的过程中遇到了一个没有分裂的节点\(x\)(也就是\(tag[x]\neq -1\)),那么就直接返回\(2^{tag[x]}*ret+k\)(注意这里的\(k\)是当前递归传进来的\(k\)并不是题目查询的原来那个值),如果说一直递归到最后(也就是底层,此时左右儿子都是\(-1\))没有遇到任何一个没有分裂的节点,那么直接\(ret\)就是答案了(因为是从\(0\)开始数的嘛)

  然后就十分愉悦地做完了,时间复杂度的话。。各项操作都是均摊\(log\)的,总的复杂度\(O(nlogn)\)

  

  代码大概长这个样子

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int N=2*(1e5)+10,SEG=N*100;
int n,T;
namespace Seg{/*{{{*/
int ch[SEG][2],sz[SEG],rt[N],tag[SEG];//tag>=0 -> full
int tot,cnt_rt,Rt;
void init(){cnt_rt=0; tot=1; tag[1]=30; sz[1]=1<<tag[1]; Rt=1;}
void newrt(){rt[++cnt_rt]=0;}
int newnode(int tg){
ch[++tot][0]=ch[tot][1]=0; tag[tot]=tg; sz[tot]=tg>=0?1<<tg:0;
return tot;
}
void pushdown(int x){
if (tag[x]==-1) return;
if (tag[x]){
ch[x][0]=newnode(tag[x]-1);
ch[x][1]=newnode(tag[x]-1);
}
else ch[x][0]=ch[x][1]=-1;
tag[x]=-1;
}
int _merge(int x,int y){
if (!x||!y) return x+y;
if (ch[x][0]!=-1){
ch[x][0]=_merge(ch[x][0],ch[y][0]);
ch[x][1]=_merge(ch[x][1],ch[y][1]);
}
sz[x]+=sz[y];
return x;
}
bool Free(int x){
if (x>cnt_rt||!rt[x]) return false;
Rt=_merge(Rt,rt[x]);
rt[x]=0;
return true;
}
void _split(int x,int &now,int k){
now=newnode(0); sz[now]=0;
pushdown(x);
if (ch[x][0]==-1) return;
tag[now]=-1; sz[now]=k;
sz[x]-=k;
if (ch[x][0]&&k<sz[ch[x][0]])
_split(ch[x][0],ch[now][0],k);
else{
k-=sz[ch[x][0]];
ch[now][0]=ch[x][0]; ch[x][0]=0;
_split(ch[x][1],ch[now][1],k);
}
}
bool alloc(int k){
newrt();
if (sz[Rt]<k) return false;
_split(Rt,rt[cnt_rt],k);
return true;
}
void _query(int x,int k,int &ret){
if (ch[x][0]==-1) return;
if (tag[x]!=-1) {ret=ret*(1<<tag[x])+k;return;}
ret*=2;
if (ch[x][0]&&k<sz[ch[x][0]]) _query(ch[x][0],k,ret);
else _query(ch[x][1],k-sz[ch[x][0]],++ret);
}
bool access(int x,int k,int &ret){
if (x>cnt_rt||!rt[x]||k>=sz[rt[x]]) return false;
ret=0;
_query(rt[x],k,ret);
return true;
}
}/*}}}*/ int main(){
#ifndef ONLINE_JUDGE
freopen("a.in","r",stdin);
#endif
int x,p,k,tmp,op;
scanf("%d",&T);
for (int o=1;o<=T;++o){
scanf("%d",&n);
Seg::init();
for (int i=1;i<=n;++i){
scanf("%d",&op);
if (op==1){
scanf("%d",&k);
if (Seg::alloc(k)) printf("ok\n");
else printf("failed\n");
}
else if (op==2){
scanf("%d",&x);
if (Seg::Free(x)) printf("ok\n");
else printf("failed\n");
}
else{
scanf("%d%d",&x,&p);
if (Seg::access(x,p,tmp)) printf("%d\n",tmp);
else printf("failed\n");
}
}
}
}

小Q与内存的更多相关文章

  1. (2016北京集训十)【xsy1530】小Q与内存

    一道很有意思的神题~ 暴力平衡树的复杂度很对(并不),但是$2^{30}$的空间一脸屎 这题的正解是一个类似线段树的数据结构,我觉得很有创新性Orz 首先可以想到一种暴力就是用一个点代表一个区间,然后 ...

  2. [2016北京集训测试赛5]小Q与内存-[线段树的神秘操作]

    Description Solution 哇真的异常服气..线段树都可以搞合并和拆分的啊orzorz.神的世界我不懂 Code #include<iostream> #include< ...

  3. 【二分图】ZJOI2007小Q的游戏

    660. [ZJOI2007] 小Q的矩阵游戏 ★☆   输入文件:qmatrix.in   输出文件:qmatrix.out   简单对比 时间限制:1 s   内存限制:128 MB [问题描述] ...

  4. 重庆OI2017 小 Q 的棋盘

    小 Q 的棋盘 时间限制: 1 Sec  内存限制: 512 MB 题目描述 小Q正在设计一种棋类游戏.在小Q设计的游戏中,棋子可以放在棋盘上的格点中.某些格点之间有连线,棋子只能在有连线的格点之间移 ...

  5. 如何让手游内存占用更小?从内存消耗iOS实时统计开始

    为什么iOS内存使用过多会崩溃,性能会下降?腾讯游戏学院专家Devlin在本文给了解释,如何让手游内存占用更小?从内存消耗iOS实时统计开始. 一.问题 在之前的手游项目中,内存使用过多,都开始崩溃了 ...

  6. 平面直接坐标系线段相交问题(小Q(钟神)的问题)

    [问题描述] 小 Q 对计算几何有着浓厚的兴趣.他经常对着平面直角坐标系发呆,思考一些有趣的问题.今天,他想到了一个十分有意思的题目:首先,小 Q 会在?轴正半轴和?轴正半轴分别挑选?个点.随后,他将 ...

  7. hdu---(4515)小Q系列故事——世界上最遥远的距离(模拟题)

    小Q系列故事——世界上最遥远的距离 Time Limit: 500/200 MS (Java/Others)    Memory Limit: 65535/32768 K (Java/Others)T ...

  8. HD4505小Q系列故事——电梯里的爱情

    Problem Description 细心的同事发现,小Q最近喜欢乘电梯上上下下,究其原因,也许只有小Q自己知道:在电梯里经常可以遇到他心中的女神HR. 电梯其实是个很暧昧的地方,只有在电梯里,小Q ...

  9. hdu4505小Q系列故事——电梯里的爱情

    小Q系列故事——电梯里的爱情 Time Limit: 300/100 MS (Java/Others)    Memory Limit: 65535/32768 K (Java/Others)Tota ...

随机推荐

  1. Python接口测试实战1(下)- 接口测试工具的使用

    如有任何学习问题,可以添加作者微信:lockingfree 课程目录 Python接口测试实战1(上)- 接口测试理论 Python接口测试实战1(下)- 接口测试工具的使用 Python接口测试实战 ...

  2. java.lang.Boolean.valueOf(String s)

    简单说,就是s为true(这四个字母大小写任意)时,返回值为true,否则为false public class one { public static void main(String[] args ...

  3. WebGL中使用window.requestAnimationFrame创建主循环

    今天总结记录一下WebGL中主循环的创建和作用.我先说明什么是主循环,其实单纯的webgl不存在主循环这个概念,这个概念是由渲染引擎引入的,主循环就是利用一个死循环或无截止条件的递归达到定时刷新can ...

  4. Linux 优化详解

    一.引子 系统优化是一项复杂.繁琐.长期的工作,优化前需要监测.采集.测试.评估,优化后也需要测试.采集.评估.监测,而且是一个长期和持续的过程,不是说现在又花了.测试了,以后就可以一劳永逸,而不是说 ...

  5. 小白初识 - 基数排序(RadixSort)

    基数排序算是桶排序和计数排序的衍生吧,因为基数排序里面会用到这两种其中一种. 基数排序针对的待排序元素是要有高低位之分的,比如单词adobe,activiti,activiti就高于adobe,这个是 ...

  6. Eclipse将Java项目打成jar工具包

    jar包:就是别人已经写好的一些类,然后将这些类进行打包,你可以将这些jar包引入你的项目中,然后就可以直接使用这些jar包中的类和属性以及方法. jar包可分为可执行jar包和jar工具包,在这里, ...

  7. VR产业链全景图

  8. daterangepicker时间段插件

    1.序言: daterangepicker是Bootstrap的一个时间组件,使用很方便 用于选择日期范围的JavaScript组件. 设计用于Bootstrap CSS框架. 它最初是为了改善报表而 ...

  9. Macbook Pro开机黑屏了。

    问题描述:点了appstore的更新,然后重启黑屏.(说明:黑屏是屏幕没亮:灰屏是屏幕亮了是灰黑色的.) 黑屏问题大,灰屏问题小. 开机按option没反应的跳到步骤四 一.数据 苹果电脑黑屏了,想搞 ...

  10. pandas中DataFrame的ix,loc,iloc索引方式的异同

    pandas中DataFrame的ix,loc,iloc索引方式的异同 1.loc: 按照标签索引,范围包括start和end 2.iloc: 在位置上进行索引,不包括end 3.ix: 先在inde ...