hdu 2871 Memory Control

本文深入探讨了一种用于内存管理的算法,包括四种基本操作:重置、新建、释放和获取。通过构建树结构并维护关键信息,该算法有效地实现了内存的高效分配与回收。文章详细介绍了操作流程、实现策略及复杂度分析,同时提供了具体代码示例,展示了如何通过维护容器和利用树结构来优化内存管理过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Memory Control

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 3610    Accepted Submission(s): 841


Problem Description
Memory units are numbered from 1 up to N.
A sequence of memory units is called a memory block.
The memory control system we consider now has four kinds of operations:
1.  Reset Reset all memory units free.
2.  New x Allocate a memory block consisted of x continuous free memory units with the least start number
3.  Free x Release the memory block which includes unit x
4.  Get x Return the start number of the xth memory block(Note that we count the memory blocks allocated from left to right)
Where 1<=x<=N.You are request to find out the output for M operations.
 

 

Input
Input contains multiple cases.
Each test case starts with two integer N,M(1<=N,M<=50000) ,indicating that there are N units of memory and M operations.
Follow by M lines,each line contains one operation as describe above.
 

 

Output
For each “Reset” operation, output “Reset Now”.
For each “New” operation, if it’s possible to allocate a memory block,
output “New at A”,where Ais the least start number,otherwise output “Reject New”.
For each “Free” operation, if it’s possible to find a memory block occupy unit x,
output “Free from A to B”,where A and B refer to the start and end number of the memory block,otherwise output “Reject Free”.
For each “Get” operation, if it’s possible to find the xth memory blocks,
output “Get at A”,where A is its start number,otherwise output “Reject Get”.
Output one blank line after each test case.
 

 

Sample Input
6 10
New 2
New 5
New 2
New 2
Free 3
Get 1
Get 2
Get 3
Free 3
Reset
Sample Output
New at 1
Reject New
New at 3
New at 5
Free from 3 to 4
Get at 1
Get at 5
Reject Get
Reject Free
Reset Now
 
Source
 
/*

内存控制
4种操作:
1.Reset 初始化
2.New x 开辟长度为x的连续的空间,输出起始位置
3.Free x 释放包含第x字节的块,整块都释放掉
4.Get x  输出当前状态下,内存里第x块的起始位置

思路:
1.Reset 很简单,update(1,N,EMPTY,1);就可以了
        没有必要重新构树

2.New  x 对于这个操作,和Hotel这道题是一样的。
        建立树的过程中保存了lmax,rmax,max。在查询的
        过程中有一些小的技巧。

3.Free x 释放内存,开一个容器,维护这个容器的顺序。
        学到了很多容器的知识。海,以前没有学过容器
        还是学别人的。
4.Get x 也是通过维护这个容器,来得到的。

详细的见代码


*/

#include<cstdio>
#include<iostream>
#include<cstdlib>
#include<algorithm>
#include<vector>
#define EMPTY 2 //纯色  此题中代表  空的。
#define HH 1 //混色  此题中代表 被占用了。
using namespace std;



struct node
{
    int l;
    int r;
    int lmax,rmax,max;
    int len;
    int color;
}f[50003*4];
struct st
{
    int begin;
    int end;
};
vector<st>tom;


int hmax(int x,int y)
{
    return x>y? x:y;
}

bool cmp1(st n1,st n2)
{
    return n1.begin<n2.begin;
}

void build(int l,int r,int n) //建树。
{
    int mid=(l+r)/2;
    f[n].l=l;
    f[n].r=r;
    f[n].color=0;
    f[n].len=f[n].r-f[n].l+1;
    f[n].lmax=f[n].rmax=f[n].max=f[n].len;
    if(l==r)
    return;
    build(l,mid,n*2);
    build(mid+1,r,n*2+1);
}
/*
建设的过程也有一个小小的亮点,可以把
 f[n].lmax=f[n].rmax=f[n].max=f[n].len;
 用向上更新来写在build(mid+1,r,n*2+1)后,带上
*/

void make_down(int n) //向下更新
{
    if(f[n].color==EMPTY)
    {
        f[n*2].max=f[n*2].rmax=f[n*2].lmax=f[n*2].len;
        f[n*2+1].max=f[n*2+1].rmax=f[n*2+1].lmax=f[n*2+1].len;
    }
    else if(f[n].color==HH)
    {
        f[n*2].max=f[n*2].lmax=f[n*2].rmax=0;
        f[n*2+1].max=f[n*2+1].lmax=f[n*2+1].rmax=0;
    }

    f[n*2].color=f[n].color;
    f[n*2+1].color=f[n].color;

    f[n].color=0;
    f[n].lmax=f[n].rmax=f[n].max=0;

}

void make_up(node *father,node *l_child,node *r_child) //向上更新
{
    father->lmax=(l_child->lmax==l_child->len)? l_child->lmax+r_child->lmax: l_child->lmax;
    father->rmax=(r_child->rmax==r_child->len)? r_child->rmax+l_child->rmax: r_child->rmax;
    father->max=hmax(hmax(father->lmax,father->rmax),
                     hmax(l_child->max,
                          hmax(r_child->max,l_child->rmax+r_child->lmax)));
}
//为什么这道题,有个小小的亮点,没有rnum ,lnum;
//仔细一想确实是不需要的..



void update(int l,int r,int num,int n) //更新函数  区间[l,r],更新为num。
{
    int mid=(f[n].l+f[n].r)/2;
    if(f[n].l==l && f[n].r==r)
    {
        if(num==EMPTY)
        {
            f[n].lmax=f[n].rmax=f[n].max=f[n].len;
        }
        else f[n].lmax=f[n].rmax=f[n].max=0;
        f[n].color=num;
        return;
    }

    if(f[n].color!=0)
    make_down(n);
    if(mid>=r)
    update(l,r,num,n*2);
    else if(mid<l)
    update(l,r,num,n*2+1);
    else
    {
        update(l,mid,num,n*2);
        update(mid+1,r,num,n*2+1);
    }
    make_up(&f[n],&f[n*2],&f[n*2+1]);
}

int query(int max,int n)
{
    int cur=0;

    if(f[n].l==f[n].r)
    return f[n].l;
    if(f[n].color!=0) //刚开始,这个别丢了,居然Running time error。
    make_down(n);

    if(f[n*2].max>=max)
    cur=query(max,n*2);

    else if(f[n*2].rmax+f[n*2+1].lmax>=max)
    return f[n*2].r-f[n*2].rmax+1;

    else if(f[n*2+1].max>=max)
    cur=query(max,n*2+1);

    make_up(&f[n],&f[n*2],&f[n*2+1]);
    return cur;
}
/*
刚开始    左子树,
然后是    左子树右边最大值+右子树左边最大值
最后才是  右子树
*/

void make_ini(int N,int M)
{
    char a[10];
    int x,l,r,tmp;
    st hxl;
    while(M--)
    {
        scanf("%s",a);
        if(a[0]=='R')
        {
            update(1,N,EMPTY,1);
            tom.clear();
            printf("Reset Now\n");
        }
        if(a[0]=='N')
        {
            scanf("%d",&x);
            if(f[1].max<x)
            {
                printf("Reject New\n");
            }
            else
            {
                l=query(x,1);
                r=l+x-1;
                hxl.begin=l;
                hxl.end=r;
                vector<st>::iterator it;
                it=upper_bound(tom.begin(),tom.end(),hxl,cmp1);//二分查找,前提是有序。
                tom.insert(it,hxl);
                printf("New at %d\n",l);
                update(l,r,HH,1);
            }
        }
        else if(a[0]=='F')
        {
            scanf("%d",&x);
            hxl.begin=x;
            hxl.end=x;
            vector<st>::iterator it;//容器的使用啊
            it=upper_bound(tom.begin(),tom.end(),hxl,cmp1);

            tmp=it-tom.begin()-1;
            if(tmp==-1 || tom[tmp].end<x)
            printf("Reject Free\n");
            else
            {
                printf("Free from %d to %d\n",tom[tmp].begin,tom[tmp].end);
                update(tom[tmp].begin,tom[tmp].end,EMPTY,1);
                tom.erase(tom.begin()+tmp);
            }
        }
        else if(a[0]=='G')
        {
            scanf("%d",&x);
            if(x>tom.size())
            printf("Reject Get\n");
            else
            printf("Get at %d\n",tom[x-1].begin);//容器的下标也是从0开始,所以要减1
        }
    }
}

int main()
{
    int N,M;
    while(scanf("%d%d",&N,&M)>0)
    {
        tom.clear();//这个必须要的。
        build(1,N,1);
        make_ini(N,M);
        printf("\n"); //!!
    }
    return 0;
}

 

转载于:https://www.cnblogs.com/tom987690183/p/3230366.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值