hdu 2871 Memory Control

线段树

题意:1到n的线段,m个操作

Reset 将所有内存清空

New x 申请一段长度为x的最左的未被占用的区间,返回它的位置,并占用它。找不到输出Reject New

Free x 找到x单元内存所在的连续的单元块,返回这个单元块的左右端点,并且清空这个单元块,如果这个单元x根本没被占用,则输出Reject Free

Get x 找到第x个单元块(而不是第x单元),返回这个单元块的起始位置即左端点

这题还是和 poj 3667 Hotel 是一样的,查询一个最左的合法区间,修改一段区间

这题使用vector按顺序来保存单元块,方便查找(可以使用二分)

而线段树主要的query和updata函数是一样的

#include <cstdio>
#include <cstring>
#include <vector>
using namespace std;
#define lch(i) ((i)<<1)
#define rch(i) ((i)<<1|1)
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
#define N 50010

struct block{
    int l,r;
};
struct node{
    int l,r;
    int mark;
    int tlen,llen,rlen;
    int mid(){
        return (l+r)>>1;
    }
    int cal_len(){
        return r-l+1;
    }
    void updata_len(){
        tlen=llen=rlen= (mark ? 0 : cal_len());
    }
};
typedef struct block Block;
typedef struct node node;
vector <Block> B;
node t[4*N];

void build(int l ,int r ,int rt)
{
    t[rt].l = l; t[rt].r = r; 
    t[rt].mark = 0;
    t[rt].updata_len();
    if(l == r) return ;
    int mid = t[rt].mid();
    int ll = lch(rt);
    int rr = rch(rt);
    build(l , mid , ll);
    build(mid+1 , r , rr);
    return ;
}

void updata(int l , int r , int val , int rt)
{
    if(t[rt].l == l && t[rt].r == r) 
    {
        t[rt].mark = val;
        t[rt].updata_len();
        return ;
    }
    int mid = t[rt].mid();
    int ll = lch(rt);
    int rr = rch(rt);
    
    if(t[rt].mark != -1)
    {
        t[ll].mark = t[rr].mark = t[rt].mark;
        t[rt].mark = -1;
        t[ll].updata_len();
        t[rr].updata_len();
    }

    if(l > mid)        updata(l , r , val , rr);
    else if(r <= mid)  updata(l , r , val , ll);
    else
    {
        updata(l , mid , val , ll);
        updata(mid+1 , r , val , rr);
    }

    t[rt].tlen = max( max(t[ll].tlen , t[rr].tlen)  ,  t[ll].rlen+t[rr].llen);
    t[rt].llen = t[ll].llen;  t[rt].rlen = t[rr].rlen;
    if(t[ll].tlen == t[ll].cal_len()) t[rt].llen += t[rr].llen;
    if(t[rr].tlen == t[rr].cal_len()) t[rt].rlen += t[ll].rlen;
    return ;
}

int query(int w , int rt)
{
    if(t[rt].l == t[rt].r)
    {
        if(w == 1) return t[rt].l;
        else       return 0;
    }

    int mid = t[rt].mid();
    int ll = lch(rt);
    int rr = rch(rt);
    
    if(t[rt].mark != -1)
    {
        t[ll].mark = t[rr].mark = t[rt].mark;
        t[rt].mark = -1;
        t[ll].updata_len();
        t[rr].updata_len();
    }

    if(t[ll].tlen >= w) 
        return query(w , ll);
    else if(t[ll].rlen + t[rr].llen >= w)
        return t[ll].r - t[ll].rlen + 1;
    else if(t[rr].tlen >= w)
        return query(w , rr);
    else
        return 0;
}

int binarysearch(int key)
{
    int low = 0;
    int high = B.size() - 1;
    while(low <= high)
    {
        int mid = (low + high) >> 1;
        if(B[mid].l <= key)
            low = mid + 1;
        else
            high = mid - 1;
    }
    return low;
    //此二分查找最终返回low,二分查找要写好,否则很难查错
    //B[low]代表的块是大于pos的,B[low-1]小于pos
    //对于添加一个新的区间,是在low这里添加,原来的low以及后面的区间往后移动
    //对于删除一个区间,是low-1,low以及后面的区间往前移动
}

int main()
{
    int n,m;
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        B.clear();
        build(1,n,1);
        while(m--)
        {
            char op[10];
            int x,pos,index;
            Block tmp;
            scanf("%s",op);
            if(!strcmp(op,"Reset"))
            {
                updata(1,n,0,1);
                B.clear();
                puts("Reset Now");
                continue;
            }

            scanf("%d",&x);
            if(!strcmp(op,"New"))
            {
                pos = query(x,1);
                if(!pos) 
                {
                    puts("Reject New");
                    continue;
                }
                printf("New at %d\n",pos);
                tmp.l = pos;  tmp.r = pos + x -1;
                index = binarysearch(pos);
                B.insert(B.begin()+index , tmp);
                updata(tmp.l , tmp.r , 1 , 1);
            }
            else if(!strcmp(op,"Free"))
            {
                index = binarysearch(x) - 1;
                if(index == -1 || B[index].r < x)
                {
                    puts("Reject Free");
                    continue;
                }
                printf("Free from %d to %d\n",B[index].l , B[index].r);
                updata(B[index].l , B[index].r , 0 , 1);
                B.erase(B.begin()+index , B.begin()+index+1);
            }
            else  //Get
            {
                if(--x >= B.size()) 
                {
                    puts("Reject Get");
                    continue;
                }
                printf("Get at %d\n",B[x].l);
            }
        }
        printf("\n");
    }
    return 0;
}
原文地址:https://www.cnblogs.com/scau20110726/p/3066405.html