HDU 2871——Memory Control(线段树,区间合并+vector+二分查找)

Memory Control

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


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
 


—————————————————分割线————————————————


题目大意:

给定一个长度为n的内存空间,有

1:New x 查询是否存在一段空的连续区间长度为x,若存在,返回最左端点,并覆盖为1,否则输出:Reject New

2:Get x 查询是否存在第x个内存块,若存在,输出该内存块的左端点,否则输出:Reject Get

3:Free x 查询是否有个内存块包含点x,若存在,则输出该内存块的区间的左右端点,然后覆盖为0,否则输出:Reject Free

4:Reset 将区间[1,n]覆盖为0


思路:


这题彩笔的我想了两天,New操作很水,就是区间合并,Get操作我用了染色+hash,统计有多少种不同颜色,每次查询到叶子节点,实现了这个功能,但是对于Free操作,彻底绝望了。。。根据题目意思,所有区间都是不相交的


然后百度之 ,vector存储每个内存块的左右端点,Get和Free二分查找左端点

注意点:vector 的insert操作是插入到位置pos的前一个位置,upper_bound是查找值x最后出现的下一个位置,如果不存在返回一个位置使得在该位置插入值x不改变序列有序


Free操作 假设该内存块的左右端点都为x,然后在vector中二分查找x,如果返回的下标为p,如果vector v[p-1]的右端点比l小,说明不存在一个内存块包含点x


Get操作直接返回 v[x-1]的左右端点就可以了


#include<iostream>
#include<cstring>
#include<cstdio>
#include<vector>
#include<algorithm>

#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
const int maxn=50010;

using namespace std;
int cov[maxn<<2],lc[maxn<<2],rc[maxn<<2],mc[maxn<<2];

typedef struct node
{
    int l,r;
    bool operator<(const node&A) const
    {
        return l<A.l;
    }
}blocks;
vector<blocks> vb;

void push_down(int rt,int m)
{
    if(cov[rt]!=-1) {
        cov[rt<<1]=cov[rt<<1|1]=cov[rt];
        lc[rt<<1]=rc[rt<<1]=mc[rt<<1]=cov[rt]? 0:(m-(m>>1));
        lc[rt<<1|1]=rc[rt<<1|1]=mc[rt<<1|1]=cov[rt]? 0:(m>>1);
        cov[rt]=-1;
    }
}
void push_up(int rt,int m)
{
    lc[rt]=lc[rt<<1];
    rc[rt]=rc[rt<<1|1];
    if(lc[rt]==m-(m>>1))
        lc[rt]+=lc[rt<<1|1];
    if(rc[rt]==m>>1)
        rc[rt]+=rc[rt<<1];
    mc[rt]=max(rc[rt<<1]+lc[rt<<1|1],max(mc[rt<<1],mc[rt<<1|1]));
}
void build(int l,int r,int rt)
{
    cov[rt]=0;
    lc[rt]=rc[rt]=mc[rt]=r-l+1;
    if(l==r) return ;
    int m=(l+r)>>1;
    build(lson);
    build(rson);
}
void update(int L,int R,int c,int l,int r,int rt)
{
    if(L<=l&&r<=R) {
        cov[rt]=c;
        lc[rt]=rc[rt]=mc[rt]=c? 0:(r-l+1);
        return ;
    }
    push_down(rt,r-l+1);
    int m=(l+r)>>1;
    if(L<=m) update(L,R,c,lson);
    if(m<R) update(L,R,c,rson);
    push_up(rt,r-l+1);
}
int query_len(int x,int l,int r,int rt)
{
    if(l==r) return l;
    push_down(rt,r-l+1);
    int m=(l+r)>>1;
    if(mc[rt<<1]>=x) return query_len(x,lson);
    else if(lc[rt<<1|1]+rc[rt<<1]>=x) return m-rc[rt<<1]+1;
    else return query_len(x,rson);
}
int main()
{
    int n,m;
    while(scanf("%d %d",&n,&m)!=EOF){
        build(1,n,1);
        vb.clear();
        char op[5];int x;
        while(m--){
            scanf("%s",op);
            if(op[0]!='R') scanf("%d",&x);
            if(op[0]=='N') {
                if(mc[1]<x) printf("Reject New\n");
                else {
                    int p=query_len(x,1,n,1);
                    printf("New at %d\n",p);
                    update(p,p+x-1,1,1,n,1);
                    blocks tmp;
                    tmp.l=p,tmp.r=p+x-1;
                    vector<blocks>::iterator iter;
                    iter=upper_bound(vb.begin(),vb.end(),tmp);
                    vb.insert(iter,tmp);
                }
            }

            if(op[0]=='F') {
                blocks tmp;
                tmp.l=tmp.r=x;
                vector<blocks>::iterator iter;
                iter=upper_bound(vb.begin(),vb.end(),tmp);
                int p=iter-vb.begin()-1;
                if(p==-1||vb[p].r<x) printf("Reject Free\n");
                else {
                    printf("Free from %d to %d\n",vb[p].l,vb[p].r);
                    update(vb[p].l,vb[p].r,0,1,n,1);
                    vb.erase(vb.begin()+p);
                }
            }

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

            if(op[0]=='R') {
                update(1,n,0,1,n,1);
                vb.clear();
                printf("Reset Now\n");
            }
        }
        printf("\n");
    }
    return 0;
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值