標籤:acm 線段樹 合并 stl
這道題在網上搜了一下題解,別人說是比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 55555struct 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 10New 2New 5New 2New 2Free 3Get 1Get 2Get 3Free 3Reset*/
這道線段樹題想法真心不錯,不過搞了我好久才看懂。。。
希望能吸取好的經驗,加油!
著作權聲明:本文為博主原創文章,未經博主允許不得轉載。
hdu 2871 Memory Control(成段更新,區間合并)