HDU2871Memory Control(线段树)

来源:互联网 发布:c语言四大圣经先后顺序 编辑:程序博客网 时间:2024/06/07 22:37

题目点这里

------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

题目大意:

有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表示这个占有内存的段的头和尾;

Get是得到第x个区间的头地址,相当于找第x小,就用size表示由1-n的内存段数,由2分查找解决;

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;

------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

反正啦,这个题是个很经典的裸线段树~~~~~~~~~


1 0
原创粉丝点击