HDU2871Memory Control(线段树)

题目点这里

------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

题目大意:

有n个内存m种操作;

New x :从内存编号1开始分配一个x的空间,如果能则输出这个区间的头地址,如果不能则输出Reject New;

Free x:释放包含x的那个区间,并且输出那个区间的头地址与尾地址,x这个地方不能被释放则输出Reject Free;

Get x:得到第x个区间的头地址,如果这个区间不存在,输出Reject Get;

Reset:释放所有内存清除;

------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

思路:

New是找一个x的连续内存那么就用lsum,rsum,sum来维护连续的值;

Free是寻找关于x的最大连续内存的头地址和尾地址,那么就用begin和end表示这个占有内存的段的头和尾;

Get是得到第x个区间的头地址,相当于找第x小,就用size表示由1-n的内存段数,由2分查找解决;

Reset不再说明;

------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

代码:

#include <cstdio>
#include <iostream>
#include <cstring>
using namespace std;
struct node{int l,r,ls,rs,s,cover,size,begin,end,lazy;}e[50100*4];
//ls,rs,s表示这个区间从最左(右)端开始的最大连续没被占用的内存
//size size表示这个区间有几个连续内存 
//begin,end表示这个连续内存中的头地址和尾地址 
void pushdownsize(int k)
{
    e[k<<1].size = e[k<<1|1].size = 0;
	e[k<<1].cover = e[k<<1|1].cover = 1;
    e[k].cover = 0;
}

void pushupsize(int k)
{
	e[k].size = e[k<<1].size + e[k<<1|1].size;
}

void pushdown(int k)
{
	e[k<<1].lazy = e[k<<1|1].lazy = e[k].lazy;
	e[k<<1].s = e[k<<1].ls = e[k<<1].rs = (e[k<<1].r-e[k<<1].l+1)*e[k<<1].lazy;
	e[k<<1|1].s = e[k<<1|1].ls = e[k<<1|1].rs = (e[k<<1|1].r - e[k<<1|1].l+1)*e[k<<1|1].lazy;
	e[k<<1].begin = e[k<<1|1].begin = e[k].begin;
	e[k<<1|1].end = e[k<<1].end = e[k].end;//一段内存里的所有点的begin和end的是这段内存的头尾地址 
	e[k].lazy = -1;
}

void pushup(int k)
{
	e[k].ls = e[k<<1].ls;
	e[k].rs = e[k<<1|1].rs;
	if(e[k].ls == e[k<<1].r-e[k<<1].l+1)e[k].ls += e[k<<1|1].ls;
	if(e[k].rs == e[k<<1|1].r-e[k<<1|1].l+1)e[k].rs += e[k<<1].rs;
	e[k].s = max(max(e[k<<1].s,e[k<<1|1].s),e[k<<1].rs+e[k<<1|1].ls);
}

void count(int k,int ret,int w)
{
	if(e[k].l == e[k].r)
	{
		e[k].size = w;
		return;
	}
	if(e[k].cover)pushdownsize(k);
	int mid = (e[k].l + e[k].r)>>1;
	if(ret > mid)count(k<<1|1,ret,w);
	if(ret <= mid)count(k<<1,ret,w);
	pushupsize(k);
}

void build(int k,int l,int r)
{
	e[k].l = l,e[k].r = r,e[k].lazy = -1;
	e[k].s = e[k].ls = e[k].rs = r-l+1;
	if(l == r)return;
	int mid = (l + r)>>1;
	build(k<<1,l,mid);
	build(k<<1|1,mid+1,r);
}

int find(int k,int ret)//返回长度为ret的空区间的头地址 
{
	if(e[k].l == e[k].r)return e[k].l;
	if(e[k].lazy != -1)pushdown(k);
	if(e[k<<1].s >= ret)
    return find(k<<1,ret);
    else if(e[k<<1].rs+e[k<<1|1].ls >= ret)
    return (e[k].l+e[k].r)/2-e[k<<1].rs+1;
    else if(e[k<<1|1].s >= ret)
    return find(k<<1|1,ret);
    pushup(k);
}

void updata(int k,int l,int r,int flag,int x,int y)
{
	if(e[k].l == l && e[k].r == r)
	{
		e[k].s = e[k].ls = e[k].rs = (e[k].r-e[k].l+1)*flag;
		e[k].begin = x,e[k].end = y;
		e[k].lazy = flag;
		return;
	}
	if(e[k].lazy != -1)pushdown(k);
	int mid = (e[k].l+e[k].r)>>1;
	if(l > mid)updata(k<<1|1,l,r,flag,x,y);
	else if(r <= mid)updata(k<<1,l,r,flag,x,y);
	else
	{
		updata(k<<1,l,mid,flag,x,y);
		updata(k<<1|1,mid+1,r,flag,x,y);
	}
	pushup(k);
}

int search(int k,int ret)//返回关于ret所在的线段树上的代号 
{
	if(e[k].l == e[k].r && e[k].l == ret)return k;
	if(e[k].lazy != -1)pushdown(k);
	int mid = (e[k].l+e[k].r)>>1;
	if(ret > mid)return search(k<<1|1,ret);
	else if(ret <= mid)return search(k<<1,ret);
	pushup(k);
}

int Get(int k,int ret)//找第ret小 
{
	if(e[k].l == e[k].r)return e[k].l;
	if(e[k].cover)pushdownsize(k);
	if(e[k<<1].size >= ret)return Get(k<<1,ret);
	else return Get(k<<1|1,ret-e[k<<1].size);
	pushupsize(k);
}

int main()
{	
	char s[20];int n,m,ret;
	while(scanf("%d%d",&n,&m)!=EOF)
	{
		memset(e,0,sizeof(e));
		build(1,1,n);
		for(int i = 1;i <= m;i++)
		{
			scanf("%s",s);
		    if(!strcmp(s,"Reset"))
	     	{
		    	puts("Reset Now");
		    	updata(1,1,n,1,0,0);
			    e[1].cover = 1;
			    e[1].size = 0;
		    }
		    if(!strcmp(s,"New"))
		    {
		    	scanf("%d",&ret);
		    	if(ret > e[1].s)puts("Reject New");
		    	else
		    	{
		    		int res = find(1,ret);
		    		printf("New at %d\n",res);
		    		updata(1,res,res+ret-1,0,res,res+ret-1);
		    		count(1,res,1);
		    	}
	    	}
		    if(!strcmp(s,"Free"))
		    {
		    	scanf("%d",&ret);
		    	int cnt = search(1,ret);
		    	if(e[cnt].begin==0)puts("Reject Free");
		    	else
		    	{
		    		printf("Free from %d to %d\n",e[cnt].begin,e[cnt].end);
		    		count(1,e[cnt].begin,0);
			    	updata(1,e[cnt].begin,e[cnt].end,1,0,0);
		    	}
			
	    	}
	    	if(!strcmp(s,"Get"))
	    	{
	    		scanf("%d",&ret);
	    		if(ret > e[1].size)puts("Reject Get");
	    		else printf("Get at %d\n",Get(1,ret));
	    	}
        }
        puts("");
	}
	return 0;
}

------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

刷题感悟:

找第K个数在线段树中的操作

关于区间的信息的保存:1.用lsum,rsum,sum来维护连续段;

                                    2.寻找长度并修改,就返回头地址;

                                    3,用begin和end维护头尾地址;

!strcmp(s,""):若s==“ ”返回值为-1;

------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

反正啦,这个题是个很经典的裸线段树~~~~~~~~~


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值