hdu 2871 Memory Control 线段树

Memory Control

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


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
 

Source
 

Recommend
gaojie

HDU 2871

 

迄今做的最难的线段树,其实就是HOTEL的加强版,甚至于HOTEL3个函数都没有任何变化。

内存共四个指令,第一次是New  x就是找一段长为X的最左边的区间,这个和HOTEL是没有区别,还是用那三个函数找到最左边的区间并加以更新,ST=1

第二个指令是Free  x就是找一个包含X的区间,咋一看以为要重写一个QUERY函数,其实没有必要,使用VECTOR数组保存下每次占领的区间,并且由于VECTOR是向量,可以删除中间的,并任意在中间加区间,十分方便。那我们现在向量里找到那个区间,接着进行更新,ST=0

第三个指令是Get x就是找到第X个区间的范围,用VECTOR的记录很快就能找到

第四个指令Reset,很方面,更新一下即可

 

另外就是初始化一定要小心

还有就是二分极其容易错,要十分小心

#include<stdio.h>

#include<string.h>

#include<vector>

#define LL(x) (x<<1)

#define RR(x) (x<<1|1)

using namespace std;

 

struct Edge

{

    int start,end;

};

vector < Edge > tt;

struct Seg_Tree

{

    int l,r,st;

    int cval,lval,rval;

    void doit() {  cval=lval=rval=(st==1? 0 : dis() );  }

    int dis()   {  return (r-l+1);  }

    int mid()   {  return (l+r)/2; }

}tree[50010*3];

int n,m;

 

void build(int left,int right,int idx)

{

     tree[idx].l=left;

     tree[idx].r=right;

     tree[idx].st=-1;

     tree[idx].doit();

     if(left==right)  return ;

     int mid=tree[idx].mid();

     build(left,mid,LL(idx));

     build(mid+1,right,RR(idx));

}

 

void update(int left,int right,int st,int idx)

{

     if(left<=tree[idx].l&&right>=tree[idx].r)

     {

         tree[idx].st=st;

         tree[idx].doit();

         return ;

     }

     if(tree[idx].st!=-1)

     {

         tree[LL(idx)].st=tree[RR(idx)].st=tree[idx].st;

         tree[LL(idx)].doit();

         tree[RR(idx)].doit();

         tree[idx].st=-1;

     }

     int mid=tree[idx].mid();

     if(mid>=left)  update(left,right,st,LL(idx));

     if(mid<right)  update(left,right,st,RR(idx));

     tree[idx].cval=max(tree[LL(idx)].rval+tree[RR(idx)].lval,

                        max(tree[LL(idx)].cval,tree[RR(idx)].cval));

     tree[idx].lval=tree[LL(idx)].lval;

     if(tree[LL(idx)].cval==tree[LL(idx)].dis()) tree[idx].lval+=tree[RR(idx)].lval;

     tree[idx].rval=tree[RR(idx)].rval;

     if(tree[RR(idx)].cval==tree[RR(idx)].dis()) tree[idx].rval+=tree[LL(idx)].rval;

}

 

int query(int x,int idx)

{

     if(tree[idx].l==tree[idx].r)

     {

         /*if(tree[idx].cval==x)*/  return tree[idx].l;

         //else return 0;

     }

 

     if(tree[idx].st!=-1)

     {

         tree[LL(idx)].st=tree[RR(idx)].st=tree[idx].st;

         tree[LL(idx)].doit();

         tree[RR(idx)].doit();

         tree[idx].st=-1;

     }

     int mid=tree[idx].mid();

     if(tree[LL(idx)].cval>=x)  return query(x,LL(idx));

     else if(tree[LL(idx)].rval+tree[RR(idx)].lval>=x)

     return tree[LL(idx)].r-tree[LL(idx)].rval+1;

     else if(tree[RR(idx)].cval>=x) return query(x,RR(idx));

     else return 0;

}

 

int half_search(int x)

{

    int left=0;

    int right=tt.size()-1;

    while(left<=right)

    {

        int mid=(left+right)>>1;

        if(tt[mid].start<=x)  left=mid+1;

        else if(tt[mid].start>x) right=mid-1;

        //else  break;

    }

    return left;

}

 

int main()

{

    while(scanf("%d%d",&n,&m)!=EOF)

    {

        memset(tree,0,sizeof(tree));

        tt.clear();

        build(1,n,1);

        for(int i=1;i<=m;i++)

        {

            char str[10];

            scanf("%s",str);

            if(strcmp(str,"Reset")==0)

            {

                update(1,n,0,1);

                tt.clear();

                puts("Reset Now");

            }

            else if(strcmp(str,"New")==0)

            {

                int x;

                scanf("%d",&x);

                if(tree[1].cval<x)  puts("Reject New");

                else

                {

                    Edge buf;

                    buf.start=query(x,1);

                    buf.end=buf.start+x-1;

                    //printf("buf.start=%d end=%d/n",buf.start,buf.end);

                    int id=half_search(buf.start);

                    //printf("id=%d/n",id);

                    tt.insert(tt.begin()+id,buf);

                    update(buf.start,buf.end,1,1);

                    printf("New at %d/n",buf.start);

                }

            }

            else if(strcmp(str,"Free")==0)

            {

                 int x;

                 scanf("%d",&x);

                 int id=half_search(x)-1;

                 if(id<=-1||tt[id].end<x) puts("Reject Free");

                 else

                 {

                     update(tt[id].start,tt[id].end,0,1);

                     printf("Free from %d to %d/n",tt[id].start,tt[id].end);

                     tt.erase(tt.begin()+id,tt.begin()+id+1);

                 }

            }

            else if(strcmp(str,"Get")==0)

            {

                int x;

                scanf("%d",&x);

                if(x>tt.size())  puts("Reject Get");

                else

                {

                    x--;

                    printf("Get at %d/n",tt[x].start);

                }

            }

        }

        puts("");

    }

    return 0;

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值