HDU 2871 Memory Control(线段树·区间合并·Vector)

题意  模拟内存申请  有n个内存单元  有以下4种操作

Reset  将n个内存单元全部清空

New x  申请一个长度为x的连续内存块  申请成功就输出左端

Free x  将x所在的内存块空间释放  释放成功输出释放的内存始末位置

Get x  输出第x个内存块的起始位置

Reset 和 New 都是基本的区间合并知识  比较简单  Free和Get需要知道内层块的位置  所以我们在New的时候要将申请的内存块的始末位置都存起来  两个内层块不会相交  这样就能通过二分找到需要的内层块了  Free后要删去对应的内存块   用vector是为了使Get操作能在O(1)时间内完成  用List的话插入删除快一些但是Get就慢了  所以随便用什么来保存被占的内层块  相对来说vector比较容易实现

#include <cstdio>
#include <vector>
#include <algorithm>
#define lc p<<1, s, mid
#define lp p<<1
#define rc p<<1|1, mid + 1, e
#define rp p<<1|1
#define mid ((s+e)>>1)
using namespace std;
const int N = 50005;
int len[N << 2], lle[N << 2], lri[N << 2], setv[N << 2];

struct Block //内层块结构体
{
    int l, r;
    bool operator< (const Block &b) const{
        return l < b.l;
    }
} block;
vector<Block> vb;
vector<Block>::iterator it;

void pushup(int p, int s, int e)
{
    len[p] = max(len[lp], len[rp]);
    len[p] = max(len[p], lri[lp] + lle[rp]);
    lle[p] = lle[lp], lri[p] = lri[rp];
    if(lle[p] == mid - s + 1) lle[p] += lle[rp];
    if(lri[p] == e - mid)  lri[p] += lri[lp];
}

void pushdown(int p, int s, int e)
{
    if(setv[p] == -1) return;
    setv[lp] = setv[rp] = setv[p];
    len[lp] = lle[lp] = lri[lp] = setv[p] * (mid - s + 1);
    len[rp] = lle[rp] = lri[rp] = setv[p] * (e - mid);
    setv[p] = -1;
}

void build(int p, int s, int e)
{
    setv[p] = -1;
    if(s == e)
    {
        len[p] = lle[p] = lri[p] = 1;
        return;
    }
    build(lc);
    build(rc);
    pushup(p, s, e);
}

void update(int p, int s, int e, int l, int r, int v)
{
    if(l <= s && e <= r)
    {
        setv[p] = v;
        len[p] = lle[p] = lri[p] = v * (e - s + 1);
        return;
    }
    pushdown(p, s, e);
    if(l <= mid) update(lc, l, r, v);
    if(r > mid) update(rc, l, r, v);
    pushup(p, s, e);
}

int query(int p, int s, int e, int v)
{
    if(s == e) return s;
    pushdown(p, s, e);
    if(len[lp] >= v) return query(lc, v);
    if(lri[lp] + lle[rp] >= v) return mid + 1 - lri[lp];
    return query(rc, v);
}

int main()
{
    int n, m, x, p;
    char op[10];
    while(~scanf("%d%d", &n, &m))
    {
        build(1, 1, n);
        vb.clear();
        while(m--)
        {
            scanf("%s", op);

            if(op[0] == 'R') //Reset
            {
                update(1, 1, n, 1, n, 1); //用build会TLE
                vb.clear();
                puts("Reset Now");
            }

            if(op[0] == 'N')  //New
            {
                scanf("%d", &x);
                if(len[1] < x) puts("Reject New");
                else
                {
                    p = query(1, 1, n, x);
                    printf("New at %d\n", p);
                    update(1, 1, n, p, p + x - 1, 0);

                    block.l = p;
                    block.r = p + x - 1;
                    it = upper_bound(vb.begin(), vb.end(), block);
                    //找到第一个起点大于p的位置 确保插入后还是升序的
                    vb.insert(it, block);
                }
            }

            if(op[0] == 'G')  //Get
            {
                scanf("%d", &x);
                if(x > vb.size()) puts("Reject Get");
                else printf("Get at %d\n", vb[x - 1].l);
            }

            if(op[0] == 'F') //Free
            {
                scanf("%d", &x);
                block.l = block.r = x;
                it = upper_bound(vb.begin(), vb.end(), block);
                int i = it - vb.begin() - 1;
                if(i < 0 || vb[i].r < x) puts("Reject Free");
                else
                {
                    printf("Free from %d to %d\n", vb[i].l, vb[i].r);
                    update(1, 1, n, vb[i].l, vb[i].r, 1);
                    vb.erase(--it);
                }
            }
        }
        puts("");
    }
    return 0;
}

Memory Control

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

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-12-23 15:11:11

HDU 2871 Memory Control(线段树·区间合并·Vector)的相关文章

hdu 2871 Memory Control(线段树)

题目链接:hdu 2871 Memory Control 题目大意:模拟一个内存分配机制. Reset:重置,释放所有空间 New x:申请内存为x的空间,输出左地址 Free x:释放地址x所在的内存块 Get x:查询第x个内存块,输出左地址 解题思路:一开始全用线段树去做,写的乱七八糟,其实只要用线段树维护可用内存.然后用户一个vector记录所有的内存块. #include <cstdio> #include <cstring> #include <vector>

HDU 2871 Memory Control (线段树,区间合并)

http://acm.hdu.edu.cn/showproblem.php?pid=2871 Memory Control Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 4418    Accepted Submission(s): 1056 Problem Description Memory units are numbered

HDU 5316 Magician(线段树区间合并入门)

本文纯属原创,转载请注明出处谢谢.http://blog.csdn.net/zip_fan. 题目传送门:http://acm.hdu.edu.cn/showproblem.php?pid=5316 Time Limit: 18000/9000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) Problem Description Fantasy magicians usually gain their ability

HDU 5316——Magician——————【线段树区间合并区间最值】

Magician Time Limit: 18000/9000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)Total Submission(s): 1613    Accepted Submission(s): 470 Problem Description Fantasy magicians usually gain their ability through one of three usual methods:

HDU - 3308 - LCIS (线段树 - 区间合并)

题目传送:LCIS 线段树,区间合并,一次过啦,没有纠结,这几天过的最愉快的一个题 思路:求最长连续上升子序列,外带单点更新,经典的线段树题目.具体看代码注释 AC代码: #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #include <cmath> #include <queue> #include <stack>

hdu 4453 约会安排(线段树区间合并)

约会安排 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65535/32768 K (Java/Others)Total Submission(s): 433    Accepted Submission(s): 145 Problem Description 寒假来了,又到了小明和女神们约会的季节. 小明虽为屌丝级码农,但非常活跃,女神们常常在小明网上的大段发言后热情回复“呵呵”,所以,小明的最爱就是和女神们约会.与此同时,也有

HDU 1540 POJ 2892 线段树区间合并

给出N个点,M次操作,N个点开始在一条线上链式相连 D操作  把某点删除掉 Q操作  询问某点一共可以连接多少个点 R操作  把上一次删除的点还原 线段树处理区间合并 分别记录每个区间的左端连续最长和右端连续最长 #include "stdio.h" #include "string.h" struct node { int l,r,lx,rx,x; }data[200010]; int mark[50100]; int Max(int a,int b) { if

HDU 1540 Tunnel Warfare(线段树 区间合并 最大连续区间)

题意  有n个连在一起的地道  接下来有m个操作  D x 炸掉x号地道  炸掉后x所在的区间就不连续了  Q x 查询输出包括x的最大连续区间长度   R修复最后一个被炸的地道  注意输入R时可能并没有需要修复的地道 线段树的区间合并问题  线段树要维护3个信息 len  对应区间的最大连续长度 ll  对应区间最左端的一段连续长度 lr  对应区间最右端的一段连续长度 那么双亲节点的这些信息和孩子节点有什么关系呢  容易发现 双亲的len 是 左孩子的len 右孩子的len  左孩子的右端长

hdu 3397 Sequence operation (线段树 区间合并 多重标记)

链接:http://acm.hdu.edu.cn/showproblem.php?pid=3397 题意: 给你一串01串,有5种操作 0. 区间全部变为0 1.区间全部变为1 2.区间异或 3.询问区间1的个数 4.询问区间被最长连续1的长度 思路: 这5个操作都是比较基础的线段树操作,难点在于有两种修改操作,这类题之前也写过,之前是乘法和加法,这个是区间亦或和区间更新值,但是思路是可以借鉴的,我们要推出这两个操作的关系,这样才能维护好这两个标记,我们用两个标记:same , rev ,分别表