hdu 2871 Memory Control(成段更新,区间合并)

这道题在网上搜了一下题解,别人说是比hdu hotel还要变态的一题。

既然是变态题,因为它综合了线段树的几乎所有操作。

这道题的题意是:

有如下几个操作:

1:首先是Reset操作,这个操作代表的是把所有的内存空间全部都清空。

2:New x:代表的是分配一个x个内存空间,如果有内存空间的话,则输出那个内存空间的最左边的那个端点。否则,则输出Reject New

3:Free x:代表的是释放含有x这个数的内存空间。如果这个内存空间已经被释放了,那么就输出Reject Free

4:Get x:代表的是返回第x个内存区间的开始位置

1)Reset操作:我们可以把所有的区间先update一遍,update和hotel一样,就是代表把那个区间清零,另外还有把vector清空。其中vector的G这个数组是为了保存每个区间的起始于结束位置(这里区间的起始与结束用STL的vector来保存,因为vector的清空某一段区间比较方便

2)New操作:首先我们先得判断一下要分配的x的长度是否小于等于tree[1].ms(总区间的现有分配长度,如果这个不满足直接是否定的。

至于查找开始点的话,那么就query下,这个和hotel是一样的。注意别忘了pushdown函数在操作的过程中。

int query(int v,int len){
    if(tree[v].l==tree[v].r) return tree[v].l;
    pushdown(v);
    int mid=(tree[v].l+tree[v].r)>>1;
    int temp=v<<1;
    if(tree[temp].ms>=len) return query(temp,len);
    else if(tree[temp].rs+tree[temp+1].ls>=len)  return tree[temp].r-tree[temp].rs+1;
    else return query(temp+1,len);
}
结束点嘛,那不是更好判断= =,因为我们已经知道了起点和区间的长度,然后结尾肯定也是可以求出来的。

现在还有一个最关键的步骤:就是给区间标记上ID,这样就可以在Get函数中方便我们查找。

一种很神奇的写法就是二分来查找它的ID是多少。

二分的原理是:

我们对起始点二分,然后就可以得到它的下标了。(注意这里下标我们是从0开始的,所以get的时候下标我们预处理时要减1)

int bin_search(int k){
    int l=0,r=G.size()-1;
    while(r>=l){
        int mid=(l+r)>>1;
        if(G[mid].s<=k) l=mid+1;  //??
        else r=mid-1;
    }
    return r;
}
最后,别忘了把起始和终止点压到第ID个区间里面去,还有把起始到终止之间的区间更新一下。

这里用了STL的vector的操作,实在是太神奇了,下次补一篇STL之vector的文,系统学一下。

<span style="white-space:pre">		</span>G.insert(G.begin()+id,buf);
                update(buf.s,buf.e,1,1);
3)Free操作,当ID是-1或者G[id].e小于x,那么是不可行的

否则输出起始与结束点,然后update(G[id].s,G[id].e,1,0),代表把他们清空。

不要忘了再vector中也进行清空。

4)Get操作,应该算是最简单的一个了把。

这里的G.size()代表的是现在有几个区间(如果原先那个区间Free掉的话,那么后面的区间会自动更新上去

注意,因为我们记录的区间是从0开始的,而题目是从1开始的,所以输出的时候要输出G[x-1].s才行。

其他的函数与hotel都是差不多的。

附上代码:

#include<stdio.h>
#include<string.h>
#include<iostream>
#include<algorithm>
#include<map>
#include<vector>
using namespace std;
#define maxn 55555
struct node{
    int l,r;
    int ls,rs,ms,flag;
}tree[maxn*4];
struct line{
    int s,e;
};
vector<line> G;
void pushup(int v){
    int temp=v<<1;
    tree[v].ls=tree[temp].ls;
    tree[v].rs=tree[temp+1].rs;
    if(tree[v].ls==tree[temp].r-tree[temp].l+1) tree[v].ls+=tree[temp+1].ls;
    if(tree[v].rs==tree[temp+1].r-tree[temp+1].l+1) tree[v].rs+=tree[temp].rs;
    tree[v].ms=max(tree[temp].ms,tree[temp+1].ms);
    tree[v].ms=max(tree[v].ms,tree[temp].rs+tree[temp+1].ls);
}
void pushdown(int v){
    int temp=v<<1;
    if(tree[v].flag!=-1){
        if(tree[v].flag){
            tree[temp].flag=tree[temp+1].flag=tree[v].flag;
            tree[temp].ls=tree[temp].rs=tree[temp].ms=0;
            tree[temp+1].ls=tree[temp+1].rs=tree[temp+1].ms=0;
        }
        if(tree[v].flag==0){
            tree[temp].flag=tree[temp+1].flag=tree[v].flag;
            tree[temp].ls=tree[temp].rs=tree[temp].ms=tree[temp].r-tree[temp].l+1;
            tree[temp+1].ls=tree[temp+1].rs=tree[temp+1].ms=tree[temp+1].r-tree[temp+1].l+1;
        }
        tree[v].flag=-1;
    }
}
void build(int l,int r,int v){
    tree[v].l=l;
    tree[v].r=r;
    tree[v].flag=-1;
    tree[v].ls=tree[v].rs=tree[v].ms=r-l+1;
    if(l==r) return;
    int mid=(tree[v].l+tree[v].r)>>1;
    int temp=v<<1;
    build(l,mid,temp);
    build(mid+1,r,temp+1);
}
void update(int l,int r,int v,int cnt){
    if(l<=tree[v].l&&tree[v].r<=r){
        if(cnt)    tree[v].ls=tree[v].rs=tree[v].ms=0,tree[v].flag=1;
        else tree[v].ls=tree[v].rs=tree[v].ms=tree[v].r-tree[v].l+1,tree[v].flag=0;
        return;
    }
    if(tree[v].flag!=-1) pushdown(v);
    int temp=v<<1;
    int mid=(tree[v].l+tree[v].r)>>1;
    if(r<=mid) update(l,r,temp,cnt);
    else if(l>mid) update(l,r,temp+1,cnt);
    else{
        update(l,mid,temp,cnt);
        update(mid+1,r,temp+1,cnt);
    }
    pushup(v);
}
int query(int v,int len){
    if(tree[v].l==tree[v].r) return tree[v].l;
    pushdown(v);
    int mid=(tree[v].l+tree[v].r)>>1;
    int temp=v<<1;
    if(tree[temp].ms>=len) return query(temp,len);
    else if(tree[temp].rs+tree[temp+1].ls>=len)  return tree[temp].r-tree[temp].rs+1;
    else return query(temp+1,len);
}
int bin_search(int k){
    int l=0,r=G.size()-1;
    while(r>=l){
        int mid=(l+r)>>1;
        if(G[mid].s<=k) l=mid+1;  //??
        else r=mid-1;
    }
    return r;
}
int main(){
    int n,m;
    while(scanf("%d%d",&n,&m)==2){
        G.clear();
        char ss[11]={0};
        int x;
        build(1,n,1);
        while(m--){
            scanf("%s",ss);
            if(!strcmp(ss,"Reset")){
                G.clear();
                update(1,n,1,0);
                printf("Reset Now\n");
            }
            else if(!strcmp(ss,"New")){
                scanf("%d",&x);
                if(tree[1].ms<x){
                    printf("Reject New\n");
                    continue;
                }
                line buf;
                buf.s=query(1,x);
                buf.e=buf.s+x-1;
                int id=bin_search(buf.s)+1;	
                printf("New at %d\n",buf.s);
                G.insert(G.begin()+id,buf);
                update(buf.s,buf.e,1,1);
            }
            else if(!strcmp(ss,"Free")){
                scanf("%d",&x);
                int id=bin_search(x);
                if(id==-1||G[id].e<x){
                    printf("Reject Free\n");
                }
                else{
                    printf("Free from %d to %d\n",G[id].s,G[id].e);
                    update(G[id].s,G[id].e,1,0);
                    G.erase(G.begin()+id,G.begin()+id+1);
                }
            }
            else if(!strcmp(ss,"Get")){
                scanf("%d",&x);
                if(x<=G.size()&&x>0){
                    printf("Get at %d\n",G[x-1].s);
                }
                else printf("Reject Get\n");
            }
        }
        puts("");
    }
}
/*
6 10
New 2
New 5
New 2
New 2
Free 3
Get 1
Get 2
Get 3
Free 3
Reset
*/


这道线段树题想法真心不错,不过搞了我好久才看懂。。。

希望能吸取好的经验,加油!





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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值