题意 模拟内存申请 有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;
}6 10 New 2 New 5 New 2 New 2 Free 3 Get 1 Get 2 Get 3 Free 3 Reset
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
版权声明:本文为博主原创文章,未经博主允许不得转载。
HDU 2871 Memory Control(线段树·区间合并·Vector)
原文地址:http://blog.csdn.net/acvay/article/details/47706629