●赘述题目

四种操作:

○Reset:将整个内存序列清空。

○New a:在尽量靠左的位置新建一个长度为a的内存块,并输出改内存块起始位置。(各个内存块即使相邻也不会合并。。)

○Free a:将a点所在的内存块清空,并输出清空的内存区间的左右端点。

○Get a:输出从左往右数的第a个内存块的起始位置。

●题解

方法:Splay在线维护

(○本来想的将序列中的每个点看作Splay树中的一个节点,然后进行区间操作。。但似乎比较麻烦。。)

○正解(erge大佬提出的思路):考虑到每个内存块不会合并的性质,将每一个内存块看作Splay树中的一个节点,且中序遍历各个节点的顺序即对应内存序列中各个内存块的从左至右的顺序(如下图)(区间化点)。然后剩下便是Splay的单点操作。

○为方便一些操作,先就加入两个边界点。

●代码

(注意NEW(insert)函数啊,有点坑坑。。)

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define MAXN 50005
#define ls tr[k][0]
#define rs tr[k][1]
using namespace std;
int fa[MAXN],tr[MAXN][2];
int l[MAXN],r[MAXN],ll[MAXN],rr[MAXN],ma[MAXN],siz[MAXN];
int tot,root;
void pushup(int k)
{
ll[k]=ls?ll[ls]:l[k]; rr[k]=rs?rr[rs]:r[k];
ma[k]=max(max(ls?ma[ls]:0,rs?ma[rs]:0),max(ls?l[k]-rr[ls]-1:0,rs?ll[rs]-r[k]-1:0));
siz[k]=1+(ls?siz[ls]:0)+(rs?siz[rs]:0);
}
void rotate(int x,int &k)
{
int y=fa[x],z=fa[y];
int l=tr[y][1]==x,r=1^l;
if(y==k) k=x;
else tr[z][tr[z][1]==y]=x;
fa[tr[x][r]]=y; fa[y]=x; fa[x]=z;
tr[y][l]=tr[x][r]; tr[x][r]=y;
pushup(y);
}
void splay(int x,int &k)
{
int y,z;
while(x!=k)
{
y=fa[x]; z=fa[y];
if(y!=k) ((tr[z][0]==y)^(tr[y][0]==x)) ? rotate(x,k):rotate(y,k);
rotate(x,k);
}
pushup(x);
}
int NEW(int &k,int last,int len,int fg,int sl)
{
if(!k)
{
k=++tot;
fa[k]=last;
l[k]=sl; r[k]=l[k]+len-1;
tr[k][0]=tr[k][1]=0;
splay(k,root);
return l[root];
}
if(fg==0) return NEW(rs,k,len,0,r[k]+1);
else if(fg==1) return NEW(ls,k,len,1,sl);
else if(ls&&ma[ls]>=len) return NEW(ls,k,len,-1,sl);
else if(ls&&l[k]-rr[ls]-1>=len) return NEW(ls,k,len,0,r[k]+1);
else if(rs&&ll[rs]-r[k]-1>=len) return NEW(rs,k,len,1,r[k]+1);
else if(rs&&ma[rs]>=len) return NEW(rs,k,len,-1,sl);
return 0;
}
int find(int k,int x)
{
if(ll[ls]<=x&&x<=rr[ls]) return find(ls,x);
else if(l[k]<=x&&x<=r[k]) return k;
else if(ll[rs]<=x&&x<=rr[rs]) return find(rs,x);
return 0;
}
int FREE(int x)
{
int k=find(root,x);
if(!k) return 0;
splay(k,root);
if(ls*rs==0) root=ls+rs,fa[root]=0;
else
{
int p=rs;
while(tr[p][0]) p=tr[p][0];
tr[p][0]=ls;
fa[ls]=p;
root=rs;
fa[root]=0;
splay(ls,root);
}
return k;
}
int GET(int k,int x)
{
if(siz[ls]>=x) return GET(ls,x); x-=siz[ls];
if(x==1) return l[k]; x-=1;
if(siz[rs]>=x) return GET(rs,x);
return 0;
}
void pre(int n)
{
root=1; tot=2;
tr[1][0]=0; tr[1][1]=2; tr[2][0]=0; tr[2][1]=0;
fa[2]=1;
l[1]=r[1]=0; l[2]=r[2]=n+1;
pushup(2); pushup(1);
}
int main()
{
int n,m,a,b; char s[10];
while(~scanf("%d%d",&n,&m))
{
pre(n);
while(m--)
{
scanf(" %s",s);
if(s[0]=='R') pre(n),printf("Reset Now\n");
else if(s[0]=='N') scanf("%d",&a),1<=a&&a<=n?b=NEW(root,0,a,-1,-1):b=0,b?printf("New at %d\n",b):printf("Reject New\n");
else if(s[0]=='F') scanf("%d",&a),1<=a&&a<=n?b=FREE(a):b=0,b?printf("Free from %d to %d\n",l[b],r[b]):printf("Reject Free\n");
else if(s[0]=='G') scanf("%d",&a),siz[root]-2>=a?b=GET(root,a+1):b=0,b?printf("Get at %d\n",b):printf("Reject Get\n");
}
printf("\n");
}
return 0;
}

●HDU 2871 Memory Control(Splay)的更多相关文章

  1. HDU 2871"Memory Control"(线段树区间和并+set.lower_bound)

    传送门 •题意 有 n 个内存单元(编号从1开始): 给出 4 种操作: (1)Reset :表示把所有的内存清空,然后输出 "Reset Now". (2)New x :表示申请 ...

  2. hdu 2871 Memory Control(伸展树splay tree)

    hdu 2871 Memory Control 题意:就是对一个区间的四种操作,NEW x,占据最左边的连续的x个单元,Free x 把x单元所占的连续区间清空 , Get x 把第x次占据的区间输出 ...

  3. hdu 2871 Memory Control(线段树)

    题目链接:hdu 2871 Memory Control 题目大意:模拟一个内存分配机制. Reset:重置,释放全部空间 New x:申请内存为x的空间,输出左地址 Free x:释放地址x所在的内 ...

  4. HDU 4441 Queue Sequence(splay)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4441 题意:一个数列,三种操作:(1)插入:找到没在当前数列中的最小的正整数i,将其插在位置p之后,并 ...

  5. hdu 2871 Memory Control (区间合并 连续段的起始位置 点所属段的左右端点)

    链接:http://acm.hdu.edu.cn/showproblem.php?pid=2871 题意: 四种操作: 1.Reset  清空所有内存2.New x  分配一个大小为x的内存块返回,返 ...

  6. HDU 1890 Robotic Sort(splay)

    [题目链接] http://acm.hdu.edu.cn/showproblem.php?pid=1890 [题意] 给定一个序列,每次将i..P[i]反转,然后输出P[i],P[i]定义为当前数字i ...

  7. HDU 2871 Memory Control

    一共4种操作 其中用线段树 区间合并,来维护连续空的长度,和找出那个位置.其他用vector维护即可 #include<cstring> #include<cstdio> #i ...

  8. HDU 5938 Four Operations(四则运算)

    p.MsoNormal { margin: 0pt; margin-bottom: .0001pt; text-align: justify; font-family: Calibri; font-s ...

  9. HDU 5775 Bubble Sort(冒泡排序)

    p.MsoNormal { margin: 0pt; margin-bottom: .0001pt; text-align: justify; font-family: Calibri; font-s ...

随机推荐

  1. Java Collections API和泛型

    Java Collections API和泛型 数据结构和算法 学会一门编程语言,你可以写出一些可以工作的代码用计算机来解决一些问题,然而想要优雅而高效的解决问题,就要学习数据结构和算法了.当然对数据 ...

  2. Java中的Integer

    包装类---Integer Integer 类在对象中包装了一个基本类型int的值.Integer类型的对象包含一个 int 类型的字段.此外,该类提供了多个方法,能在 int 类型和 String ...

  3. 学习ASP.NET Core Razor 编程系列四——Asp.Net Core Razor列表模板页面

    学习ASP.NET Core Razor 编程系列目录 学习ASP.NET Core Razor 编程系列一 学习ASP.NET Core Razor 编程系列二——添加一个实体 学习ASP.NET ...

  4. java截取一个字符串正数或倒数某个特定字符前后的内容

    取出正数第二个“.”后面的内容 public class TestCode { public static void main(String[] args) { String str ="2 ...

  5. jQuery 文档操作之prepend() 和prependTo()方法.

    //prepend() $("#btnpre").click(function(){ //该方法在被选元素的开头(仍位于内部)插入指定内容. $("div"). ...

  6. Docker学习笔记 - Docker客户端和服务端

    学习内容: Docker客户端和服务端的通讯方式:client和自定义程序 Docker客户端和服务端的连接方式:socket 演示Docker客户端和服务端之间用remote-api通讯:nc   ...

  7. 阿里云API网关(2)开放 API 并接入 API 网关

    网关指南: https://help.aliyun.com/document_detail/29487.html?spm=5176.doc48835.6.550.23Oqbl 网关控制台: https ...

  8. python开发:python字符串操作方法

    name = "my \tname is {name} and i am {year} old" capitalize:第一个单词的首字母大写的方法 print(name.capi ...

  9. JS面向对象之原型链

      对象的原型链 只要是对象就有原型 原型也是对象 只要是对象就有原型, 并且原型也是对象, 因此只要定义了一个对象, 那么就可以找到他的原型, 如此反复, 就可以构成一个对象的序列, 这个结构就被成 ...

  10. linux如何安装django

    首先在命令行下输入python 进入界面后先importdjango 如果这一步有错,说明没有django 需要我们安装 源码安装方法: 下载源码包 https://www.djangoproject ...