hdu 2871 Memory Control 线段树

题意:

给定一个n长的内存,共有4种操作:

1)Reset,清空内存。输出“Reset Now”。

2)New x,分配连续x长内存单元给该内存块,要求分配位置尽可能靠前。成功输出“New at x”,x表示内存块开始位置;否则输出“Reject New”。

3)Free x,清空包含第x个内存单元所在内存块。成功输出“Free from x to y”,x为内存块开始位置,y为内存块结束位置;否则输出“Reject Free”。

4)Get x,获得第x个内存块开始位置。存在输出“Get at x”,x表示内存块开始位置;否则输出“Reject Get”。

之后m次操作,输出每次的操作结果。

题解:

我们用线段树维护内存块存储情况,用vector维护内存块顺序。线段树结点中pre,aft分别表示这段区间从开始位置开始的最大空内存长度和从结束位置开始最大空内存长度,maxv为这段区间的最大空内存长度,setv标记是否有修改操作,其中线段树上1表示空内存,0表示被分配。每个非叶子结点的maxv都跟其叶子的maxv和pre,aft有关,所以可以很容易的维护。

在New操作时,先用New函数找到开始位置,然后用二分法(二分是必要的,不然耗时可能会爆掉)在vector中找到插入的位置。

在Free操作时,也是用二分法判断是否存在符合内存块,然后用update函数进行修改

在Reset操作时,直接用update操作清空所有内存,还有要清空vector。

在Get操作时,直接在vector中查找即可。



代码:

#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <ctime>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <map>
#include <set>
#include <queue>
using namespace std;

const int maxn=5e4+10;
struct node{
    int l,r,len;
    int pre,aft,maxv;//the number of empty memory units from left ,from right ans max
    int setv;   //sign update
}e[maxn*4];
struct block{
    int x,y;
};
vector<block>mm;
bool cmp(block a,block b)
{
    return a.x<b.x;
}
void push_down(int c)
{
    if(e[c].setv!=-1)
    {
        e[2*c].setv=e[2*c+1].setv=e[c].setv;
        e[2*c].pre=e[2*c].aft=e[2*c].maxv=(e[2*c].r-e[2*c].l+1)*e[c].setv;
        e[2*c+1].pre=e[2*c+1].aft=e[2*c+1].maxv=(e[2*c+1].r-e[2*c+1].l+1)*e[c].setv;
        e[c].setv=-1;
    }
}
void push_up(int c)
{
    if(e[2*c].pre==e[2*c].len)e[c].pre=e[2*c].pre+e[2*c+1].pre;
    else e[c].pre=e[2*c].pre;
    if(e[2*c+1].aft==e[2*c+1].len)e[c].aft=e[2*c+1].aft+e[2*c].aft;
    else e[c].aft=e[2*c+1].aft;
    e[c].maxv=max(max(e[2*c].maxv,e[2*c+1].maxv),e[2*c].aft+e[2*c+1].pre);
}
void build(int a,int b,int c)
{
    if(a==b)
    {
        e[c].l=e[c].r=a;
        e[c].len=e[c].pre=e[c].aft=e[c].maxv=b-a+1;
        e[c].setv=-1;
        return ;
    }
    int mid=(a+b)/2;
    build(a,mid,2*c);
    build(mid+1,b,2*c+1);
    e[c].l=a;e[c].r=b;e[c].len=b-a+1;
    push_up(c);
    e[c].setv=-1;
}
void update(int a,int b,int c,int val)//update interval ,value of 1 represent empty memory units
{
    if(e[c].l==a&&e[c].r==b)
    {
        e[c].setv=val;
        e[c].pre=e[c].aft=e[c].maxv=(b-a+1)*val;
        return ;
    }
    push_down(c);
    int mid=(e[c].l+e[c].r)/2;
    if(b<=mid)update(a,b,2*c,val);
    else if(a>mid)update(a,b,2*c+1,val);
    else
    {
        update(a,mid,2*c,val);
        update(mid+1,b,2*c+1,val);
    }
    push_up(c);
}
int New(int x,int c)//the operator of New,return the position of start 
{
    if(e[c].l==e[c].r)return e[c].l;
    int mid=(e[c].l+e[c].r)/2;
    push_down(c);
    if(e[2*c].maxv>=x)return New(x,2*c);
    else if(e[2*c].aft+e[2*c+1].pre>=x)return e[2*c].r-e[2*c].aft+1;
    else return New(x,2*c+1);
}
int main()
{
    int n,m;
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        char s[10];
        int i,j,k,a,b,x,ans;
        build(1,n,1);
        mm.clear();
        for(i=0;i<m;i++)
        {
            scanf("%s",s);
            if(s[0]=='R')
            {
                update(1,n,1,1);
                mm.clear();
                printf("Reset Now\n");
            }
            else if(s[0]=='N')
            {
                scanf("%d",&x);
                if(e[1].maxv<x)printf("Reject New\n");
                else
                {
                    ans=New(x,1);
                    printf("New at %d\n",ans);
                    update(ans,ans+x-1,1,0);
                    block f;
                    f.x=ans;f.y=ans+x-1;
                    vector<block>::iterator it;
                    it=upper_bound(mm.begin(),mm.end(),f,cmp);
                    mm.insert(it,f);
                }
            }
            else if(s[0]=='F')
            {
                scanf("%d",&x);
                block f;
                f.x=x;f.y=x;
                vector<block>::iterator it;
                it=upper_bound(mm.begin(),mm.end(),f,cmp);
                ans=it-mm.begin()-1;
                if(ans==-1||mm[ans].y<x)printf("Reject Free\n");
                else
                {
                    printf("Free from %d to %d\n",mm[ans].x,mm[ans].y);
                    update(mm[ans].x,mm[ans].y,1,1);
                    mm.erase(it-1);
                }
            }
            else
            {
                scanf("%d",&x);
                if(x>mm.size())printf("Reject Get\n");
                else printf("Get at %d\n",mm[x-1].x);
            }
        }
        printf("\n");
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值