hdu_2871_Memory Control(巨恶心线段树)

题目连接:http://acm.hdu.edu.cn/showproblem.php?pid=2871

题意:给你一段内存,让你操作1:Reset:重置所有内存 2:New x:申请一块X大小的内存,返回内存最左边的开头,3:free x:释放包含x单元的内存块 4:Get x:取第X块的内存首地址

题解:这题我写了一晚上,很恶心,显然用线段树维护,不过用一个Vector 来应对 free和get操作比较方便,线段树就只需要维护内存的连续长度和最大长度就行了,

ll[rt]为该区段从左边开始的连续内存长度,rr[rt]为该区间从右边开始的连续内存长度,mlen[rt]为该区间最大的连续内存长度,只有这样维护才能在线段树中任意操作区间


#include<cstdio>
#include<vector>
#include<algorithm>
using namespace std;
#define F(i,a,b) for(int i=a;i<=b;i++)
#define root 1,n,1
#define ls l,m,rt<<1
#define rs m+1,r,rt<<1|1
#define Max(a,b) ((a)>(b)?(a):(b))

struct edge{
	int l,r;
	bool operator<(const edge &b)const{return l<b.l;}
}s,e,tp;
const int maxn=50010;
int n,m,num,ll[maxn<<2],rr[maxn<<2],lazy[maxn<<2],mlen[maxn<<2];
vector<edge>Q;

inline void pup(int l,int r,int rt){
	int m=(l+r)>>1;
	mlen[rt]=Max(mlen[rt<<1],mlen[rt<<1|1]);
	mlen[rt]=Max(mlen[rt],rr[rt<<1]+ll[rt<<1|1]);
	ll[rt]=ll[rt<<1]+(ll[rt<<1]==m-l+1?ll[rt<<1|1]:0);
	rr[rt]=rr[rt<<1|1]+(rr[rt<<1|1]==r-m?rr[rt<<1]:0);
}

inline void pdown(int l,int r,int rt){
	if(lazy[rt]!=-1){
		lazy[rt<<1]=lazy[rt<<1|1]=lazy[rt];
		int m=(l+r)>>1;
		mlen[rt<<1]=ll[rt<<1]=rr[rt<<1]=(lazy[rt]==0?m-l+1:0);
		mlen[rt<<1|1]=rr[rt<<1|1]=ll[rt<<1|1]=(lazy[rt]==0?r-m:0);
		lazy[rt]=-1;
	}
}

int New(int l,int r,int rt,int num){
	if(l==r)return l;
	int m=(l+r)>>1;
	pdown(l,r,rt);
	if(mlen[rt<<1]>=num)return New(ls,num);
	else if(rr[rt<<1]+ll[rt<<1|1]>=num)return m-rr[rt<<1]+1;
	else return New(rs,num);
}

void covr(int op,int L,int R,int l,int r,int rt){//op为0是释放内存,1为占用
	if(L<=l&&r<=R){
		lazy[rt]=op,ll[rt]=rr[rt]=mlen[rt]=(op==0?r-l+1:0);
		return;
	}
	pdown(l,r,rt);
	int m=(l+r)>>1;
	if(L<=m)covr(op,L,R,ls);
	if(R>m)covr(op,L,R,rs);
	pup(l,r,rt);
}

void reset(){Q.clear(),Q.push_back(s),Q.push_back(e);covr(0,1,n,root);}

void insert(edge xx){
	int now=upper_bound(Q.begin(),Q.end(),xx)-Q.begin();
	Q.insert(Q.begin()+now,xx);
}

int main(){
	char op[20];s.l=0,s.r=0,e.l=100000,e.r=100000;
	while(~scanf("%d%d",&n,&m)){
		reset();
		while(m--){
			scanf("%s",op);
			if(op[0]!='R')scanf("%d",&num);
			if(op[0]=='N')if(mlen[1]<num)puts("Reject New");
			else{int x=New(root,num);printf("New at %d\n",x),tp.l=x,tp.r=x+num-1,covr(1,tp.l,tp.r,root),insert(tp);}
			else if(op[0]=='F'){
				tp.l=num,tp.r=num;
				int now=upper_bound(Q.begin(),Q.end(),tp)-Q.begin()-1;
				if(Q[now].l<=num&&Q[now].r>=num)
					covr(0,Q[now].l,Q[now].r,root),printf("Free from %d to %d\n",Q[now].l,Q[now].r),Q.erase(Q.begin()+now);
				else puts("Reject Free");
			}else if(op[0]=='G'){
				if(num>Q.size()-2)puts("Reject Get");
				else printf("Get at %d\n",Q[num].l);
			}else reset(),puts("Reset Now");
		}
		puts("");
	}
	return 0;
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值