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. 在Unity中使用带碰撞体的TiledMap

    虽然最近Unity2018版本推出了自己的瓦片地图,但是这个瓦片地图有点BUG,在场景内把瓦片地图铺好做成预制体,动态生成的时候居然丢失了碰撞体,于是我决定还是使用Tiled软件绘制地图并使用Tile ...

  2. Unity中StopCoroutine不起作用怎么办

    1,只有StartCoroutine使用一个字符串方法名时才能用StopCoroutine(string CoroutineName)停用. 2, public Coroutine coroutine ...

  3. 二维DCT变换

    DCT(Discrete Consine Transform),又叫离散余弦变换,它的第二种类型,经常用于信号和图像数据的压缩.经过DCT变换后的数据能量非常集中,一般只有左上角的数值是非零的,也就是 ...

  4. Linux系统网络安装——基于pxe+dhcp+nfs+tftp+kickstart

    原文发表于:2010-09-05 转载至cu于:2012-07-21 一.原理简介 PXE(preboot execute environment)工作于Client/Server的网络模式,支持工作 ...

  5. JS对字符串编码的几种方式

    函数 描述 encodeURI() 把字符串编码为 URI encodeURIComponent() 把字符串编码为 URI 组件 escape() 对字符串进行编码 上面是查询来自w3school的 ...

  6. Catch That Cow:BFS:加标记数组:不加标记数组

    Catch That Cow Problem Description Farmer John has been informed of the location of a fugitive cow a ...

  7. php 通过curl上传图片

    通过curl上传图片 PHP < 5.5: 使用 目前使用的php版本 7.1 测试无法使用 前面加@ 的方法上传文件 ,查找资料 使用 curl_setopt($ch,CURLOPT_SAFE ...

  8. Hybrid APP基础篇(四)->JSBridge的原理

    说明 JSBridge实现原理 目录 前言 参考来源 前置技术要求 楔子 原理概述 简介 url scheme介绍 实现流程 实现思路 第一步:设计出一个Native与JS交互的全局桥对象 第二步:J ...

  9. 过山车 HDU 2063 (二分图匹配裸题)

    Problem Description RPG girls今天和大家一起去游乐场玩,终于可以坐上梦寐以求的过山车了.可是,过山车的每一排只有两个座位,而且还有条不成文的规矩,就是每个女生必须找个个男生 ...

  10. HDU 5195 DZY Loves Topological Sorting 拓扑排序

    题目链接: hdu:http://acm.hdu.edu.cn/showproblem.php?pid=5195 bc(中文):http://bestcoder.hdu.edu.cn/contests ...