CodeForces 7B

我把我的思路大概写了下注释里面

原因是之前写过这样一个求助
https://www.luogu.com.cn/discuss/show/163636

所以为了省事就直接在上面改了\(QwQ\)

\(ODT\) (珂朵莉树) 实现唷(^U^)ノ~YO

虽然说没有在学ODT时的基本操作,但确实是区间缩点的思想呢

#include <iostream>
#include <cstdio>
#include <cstring>
#include <set>
#include <algorithm>
using namespace std;
#define ri register int

//这个是ODT树呢。。
//l,r是这个区间的左右边界,当然都是闭区间
//val是这个区间对应的编号,len是区间的长度
struct ODT
{
    int l, r;
    mutable int val, len;
    ODT(int L = -1, int R = -1, int V = 0, int E = 0)
    : l(L), r(R), val(V), len(E) {}
    bool operator< (const ODT& x) const
    { return l < x.l;}
};
typedef set<ODT>::iterator IT;

//n,m 如题意;xth是第x个请求成功的内存编号,当然一开始是1啦。。
set<ODT> nc;
int n, m, xth = 1;
char s[13];

//这是尝试申请内存
inline void add_nc(int le)
{
    int flag = 1;
    IT it = nc.begin();
        //找第一个可用的(0)且长度大于等于所需的内存
        //并将这段0区间分为两端
    for ( ; it != nc.end(); ++it)
    {
        if (it->val != 0) continue;
        if (it->len >= le)
        {
            int L = it->l, R = it->r, LE = it->len;
            int pos = L + le;
            nc.erase(it);
            nc.insert(ODT(L, pos-1, xth, le));
            if (pos <= R) nc.insert(ODT(pos, R, 0, LE-le));
            flag = 0;
            break;
        }
    }
        //如果没找到输出NULL,否则输出编号
    if (flag) printf("NULL\n");
    else printf("%d\n", xth), ++xth;
}

//这是删除编号为x的内存
inline void erase_nc(int x)
{
    int flag = 1;
    IT it = nc.begin();
        //寻找这段内存并赋值为零
        //(本来可以直接改变找到区间的val为0滴,但不知道为什么比删除后重新加入要慢qwq)
    for ( ; it != nc.end(); ++it)
    {
        if (it->val == x)
        {
            int L = it->l, R = it->r, LE = it->len;
            nc.erase(it);
            it = nc.insert(ODT(L, R, 0, LE)).first;
            flag = 0;
            break;
        }
    }
        //如果不存在编号输出ILLEGAL_ERASE_ARGUMENT
        //否则查看左右相邻区间val是否为0,并将其合并
    if (flag) printf("ILLEGAL_ERASE_ARGUMENT\n");
    else
    {
        if (it != nc.begin())
        {
            IT itn = it;
            --it;
            if (it->val == 0)
            {
                int L = it->l, R = itn->r, LE = it->len;
                LE += itn->len;
                nc.erase(it), nc.erase(itn);
                itn = nc.insert(ODT(L, R, 0, LE)).first;
            }
            it = itn;
        }
        IT itn = it;
        ++it;
        if (it != nc.end() && it->val == 0)
        {
            int L = itn->l, R = it->r, LE = it->len;
            LE += itn->len;
            nc.erase(it), nc.erase(itn);
            nc.insert(ODT(L, R, 0, LE));
        }
    }
}

//这是前移操作
inline void defragment()
{
    int LEO = 0;
    IT it = nc.begin();
        //将0区间删除,并累加其长度。
        //将非0区间向前移动已经删除的0区间长度之和
    for ( ; it != nc.end(); )
    {
        if(it->val == 0)
        {
            LEO += it->len;
            IT itn = it;
            ++itn;
            nc.erase(it);
            it = itn;
        } else {
            int L = it->l, R = it->r, V = it->val, LE = it->len;
            L -= LEO, R -= LEO;
            nc.erase(it);
            it = nc.insert(ODT(L, R, V, LE)).first;
            ++it;
        }
    }
    //最后如果还有0区间,将0区间加在最后面
    if(LEO) nc.insert(ODT(m-LEO+1, m, 0, LEO));
}

signed main()
{
    scanf("%d%d", &n, &m);
        //最开始都是0,即全部可使用
    nc.insert(ODT(1, m, 0, m));
    for (ri i = 1; i <= n; ++i)
    {
        //靠第一个字母就可以区分了讷。。
        scanf("%s", s);
        if (s[0] == 'a')
        {
            int x;
            scanf("%d", &x);
            add_nc(x);
        } else if (s[0] == 'e') {
            int x;
            scanf("%d", &x);
            // 一定要加这个判断!!!
			// 这里是我跌倒数次的地方!!
			// 这是为了防止一开始就erase时将我们规定的初始无内存占用状态删除
			// 所以一旦小于等于0,就直接输出 
			if (x <= 0) {
				printf("ILLEGAL_ERASE_ARGUMENT\n");
				continue;
			}
            erase_nc(x);
        } else if (s[0] == 'd') {
            defragment();
        }
    }
    return 0;
}

这是经历CSP第一届的残酷打击后我做的第一道题呢\(QwQ\)

最后愿珂朵莉长存~~~

珂朵莉树万岁!!!!

\ \ ""抱歉⋯我已经 绝对不可能再获得幸福了

\ \ \ \ \ \ \ \ \ \ 因为⋯我发现⋯

\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 其实我⋯

**\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 早就已经被幸福包围了"" **

posted @ 2020-01-21 00:08  敲可耐的螺旋藻  阅读(169)  评论(0编辑  收藏  举报