●赘述题目
四种操作:
○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; }