这道题在网上搜了一下题解,别人说是比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 */
希望能吸取好的经验,加油!
版权声明:本文为博主原创文章,未经博主允许不得转载。
hdu 2871 Memory Control(成段更新,区间合并)
原文地址:http://blog.csdn.net/acmer_hades/article/details/46742911