------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
题目大意:
有n个内存m种操作;
New x :从内存编号1开始分配一个x的空间,如果能则输出这个区间的头地址,如果不能则输出Reject New;
Free x:释放包含x的那个区间,并且输出那个区间的头地址与尾地址,x这个地方不能被释放则输出Reject Free;
Get x:得到第x个区间的头地址,如果这个区间不存在,输出Reject Get;
Reset:释放所有内存清除;
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
思路:
New是找一个x的连续内存那么就用lsum,rsum,sum来维护连续的值;
Free是寻找关于x的最大连续内存的头地址和尾地址,那么就用begin和end表示这个占有内存的段的头和尾;
Reset不再说明;
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
代码:
#include <cstdio>
#include <iostream>
#include <cstring>
using namespace std;
struct node{int l,r,ls,rs,s,cover,size,begin,end,lazy;}e[50100*4];
//ls,rs,s表示这个区间从最左(右)端开始的最大连续没被占用的内存
//size size表示这个区间有几个连续内存
//begin,end表示这个连续内存中的头地址和尾地址
void pushdownsize(int k)
{
e[k<<1].size = e[k<<1|1].size = 0;
e[k<<1].cover = e[k<<1|1].cover = 1;
e[k].cover = 0;
}
void pushupsize(int k)
{
e[k].size = e[k<<1].size + e[k<<1|1].size;
}
void pushdown(int k)
{
e[k<<1].lazy = e[k<<1|1].lazy = e[k].lazy;
e[k<<1].s = e[k<<1].ls = e[k<<1].rs = (e[k<<1].r-e[k<<1].l+1)*e[k<<1].lazy;
e[k<<1|1].s = e[k<<1|1].ls = e[k<<1|1].rs = (e[k<<1|1].r - e[k<<1|1].l+1)*e[k<<1|1].lazy;
e[k<<1].begin = e[k<<1|1].begin = e[k].begin;
e[k<<1|1].end = e[k<<1].end = e[k].end;//一段内存里的所有点的begin和end的是这段内存的头尾地址
e[k].lazy = -1;
}
void pushup(int k)
{
e[k].ls = e[k<<1].ls;
e[k].rs = e[k<<1|1].rs;
if(e[k].ls == e[k<<1].r-e[k<<1].l+1)e[k].ls += e[k<<1|1].ls;
if(e[k].rs == e[k<<1|1].r-e[k<<1|1].l+1)e[k].rs += e[k<<1].rs;
e[k].s = max(max(e[k<<1].s,e[k<<1|1].s),e[k<<1].rs+e[k<<1|1].ls);
}
void count(int k,int ret,int w)
{
if(e[k].l == e[k].r)
{
e[k].size = w;
return;
}
if(e[k].cover)pushdownsize(k);
int mid = (e[k].l + e[k].r)>>1;
if(ret > mid)count(k<<1|1,ret,w);
if(ret <= mid)count(k<<1,ret,w);
pushupsize(k);
}
void build(int k,int l,int r)
{
e[k].l = l,e[k].r = r,e[k].lazy = -1;
e[k].s = e[k].ls = e[k].rs = r-l+1;
if(l == r)return;
int mid = (l + r)>>1;
build(k<<1,l,mid);
build(k<<1|1,mid+1,r);
}
int find(int k,int ret)//返回长度为ret的空区间的头地址
{
if(e[k].l == e[k].r)return e[k].l;
if(e[k].lazy != -1)pushdown(k);
if(e[k<<1].s >= ret)
return find(k<<1,ret);
else if(e[k<<1].rs+e[k<<1|1].ls >= ret)
return (e[k].l+e[k].r)/2-e[k<<1].rs+1;
else if(e[k<<1|1].s >= ret)
return find(k<<1|1,ret);
pushup(k);
}
void updata(int k,int l,int r,int flag,int x,int y)
{
if(e[k].l == l && e[k].r == r)
{
e[k].s = e[k].ls = e[k].rs = (e[k].r-e[k].l+1)*flag;
e[k].begin = x,e[k].end = y;
e[k].lazy = flag;
return;
}
if(e[k].lazy != -1)pushdown(k);
int mid = (e[k].l+e[k].r)>>1;
if(l > mid)updata(k<<1|1,l,r,flag,x,y);
else if(r <= mid)updata(k<<1,l,r,flag,x,y);
else
{
updata(k<<1,l,mid,flag,x,y);
updata(k<<1|1,mid+1,r,flag,x,y);
}
pushup(k);
}
int search(int k,int ret)//返回关于ret所在的线段树上的代号
{
if(e[k].l == e[k].r && e[k].l == ret)return k;
if(e[k].lazy != -1)pushdown(k);
int mid = (e[k].l+e[k].r)>>1;
if(ret > mid)return search(k<<1|1,ret);
else if(ret <= mid)return search(k<<1,ret);
pushup(k);
}
int Get(int k,int ret)//找第ret小
{
if(e[k].l == e[k].r)return e[k].l;
if(e[k].cover)pushdownsize(k);
if(e[k<<1].size >= ret)return Get(k<<1,ret);
else return Get(k<<1|1,ret-e[k<<1].size);
pushupsize(k);
}
int main()
{
char s[20];int n,m,ret;
while(scanf("%d%d",&n,&m)!=EOF)
{
memset(e,0,sizeof(e));
build(1,1,n);
for(int i = 1;i <= m;i++)
{
scanf("%s",s);
if(!strcmp(s,"Reset"))
{
puts("Reset Now");
updata(1,1,n,1,0,0);
e[1].cover = 1;
e[1].size = 0;
}
if(!strcmp(s,"New"))
{
scanf("%d",&ret);
if(ret > e[1].s)puts("Reject New");
else
{
int res = find(1,ret);
printf("New at %d\n",res);
updata(1,res,res+ret-1,0,res,res+ret-1);
count(1,res,1);
}
}
if(!strcmp(s,"Free"))
{
scanf("%d",&ret);
int cnt = search(1,ret);
if(e[cnt].begin==0)puts("Reject Free");
else
{
printf("Free from %d to %d\n",e[cnt].begin,e[cnt].end);
count(1,e[cnt].begin,0);
updata(1,e[cnt].begin,e[cnt].end,1,0,0);
}
}
if(!strcmp(s,"Get"))
{
scanf("%d",&ret);
if(ret > e[1].size)puts("Reject Get");
else printf("Get at %d\n",Get(1,ret));
}
}
puts("");
}
return 0;
}
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
刷题感悟:
找第K个数在线段树中的操作
关于区间的信息的保存:1.用lsum,rsum,sum来维护连续段;
2.寻找长度并修改,就返回头地址;
3,用begin和end维护头尾地址;
!strcmp(s,""):若s==“ ”返回值为-1;
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
反正啦,这个题是个很经典的裸线段树~~~~~~~~~