HDU 1540 Tunnel Warfare
這道題中我們用0表示該點是好的,1表示已經被毀壞。那麼這道題就是更新點尋找區間的線段樹,但是為了能夠求某個點連續的0的個數,我們線上段樹內需要記一個區間左右端點連續的0的個數。這樣當查詢的時候,分成兩邊來查詢,然後判斷一下點本身是否為被毀壞就行了。
詳細見代碼:
#include <iostream>#include <cstring>#include <cstdlib>#include <cstdio>#include <stack>#define MAX 50010#define lson l,m,k<<1#define rson m+1,r,k<<1|1using namespace std;typedef struct SEG{ int dt; int lnum,rnum;}Seg;Seg seg[MAX<<2];void PushUp(int l,int r,int k){ if(seg[k<<1].dt==seg[k<<1|1].dt) seg[k].dt=seg[k<<1].dt; else seg[k].dt=-1; int m = (l+r)>>1; if(seg[k<<1].lnum==(m-l+1)) seg[k].lnum=seg[k<<1].lnum+seg[k<<1|1].lnum; else seg[k].lnum=seg[k<<1].lnum; if(seg[k<<1|1].rnum==(r-m)) seg[k].rnum=seg[k<<1|1].rnum+seg[k<<1].rnum; else seg[k].rnum=seg[k<<1|1].rnum;}void PushDown(int l,int r,int k){ if(seg[k].dt>-1) { int m = (l+r)>>1; seg[k<<1].dt=seg[k<<1|1].dt; if(seg[k].dt==0) { seg[k<<1].lnum=seg[k<<1].rnum=m-l+1; seg[k<<1|1].lnum=seg[k<<1|1].rnum=r-m; } else { seg[k<<1].lnum=seg[k<<1].rnum=0; seg[k<<1|1].lnum=seg[k<<1|1].rnum=0; } seg[k].dt=-1; }}void Init(int l,int r,int k){ seg[k].dt=0; if(l==r) { seg[k].lnum=seg[k].rnum=1; return ; } int m = (l+r)>>1; Init(lson); Init(rson); PushUp(l,r,k);}void Update(int id,int v,int l,int r,int k){ if(l==r&&l==id) { seg[k].dt=v; if(v==0) seg[k].lnum=seg[k].rnum=1; else seg[k].lnum=seg[k].rnum=0; return ; } PushDown(l,r,k); int m = (l+r)>>1; if(id<=m) Update(id,v,lson); else Update(id,v,rson); PushUp(l,r,k);}Seg Query(int ll,int rr,int l,int r,int k){ if(ll>rr) { Seg ans ; ans.lnum=ans.rnum=0; return ans; } if(ll==l&&rr==r) { return seg[k]; } PushDown(l,r,k); int m = (l+r)>>1; Seg ans; if(rr<=m) ans = Query(ll,rr,lson); else if(ll>m) ans = Query(ll,rr,rson); else { Seg a = Query(ll,m,lson); Seg b = Query(m+1,rr,rson); if(a.lnum==(m-ll+1)) ans.lnum=a.lnum+b.lnum; else ans.lnum=a.lnum; if(b.rnum==(rr-m)) ans.rnum=b.rnum+a.rnum; else ans.rnum=b.rnum; } PushUp(l,r,k); return ans;}stack <int> st;int main(){ int n,m; char op[4]; int a; while(scanf("%d%d",&n,&m)!=EOF) { while(!st.empty()) st.pop(); Init(1,n,1); while(m--) { scanf("%s",op); if(op[0]!='R') scanf("%d",&a); if(op[0]=='D') { st.push(a); Update(a,1,1,n,1); } else if(op[0]=='R') { int t = st.top(); st.pop(); Update(t,0,1,n,1); } else { Seg ans1 = Query(1,a-1,1,n,1); Seg ans2 = Query(a,n,1,n,1); if(ans2.lnum==0) printf("0\n"); else { printf("%d\n",ans1.rnum+ans2.lnum); } } } } return 0;}
HDU 2871 Memory Control
http://acm.hdu.edu.cn/showproblem.php?pid=2871
這道題其實就是維護一個區間連續的0的情況,這裡包括將一個區間置為0或1,;然後就是對於一個塊,有一個區間表示它所佔用的記憶體單元,然後需要輸出編號為idx的單元所在的塊的起始標號和終止標號;還有一個就是尋找第x個塊的起始地址。
對於前面第一個要求,直接使用線段樹進行維護,記法和Hotel是一樣的。
對於其他的兩個操作,我們已經很清楚的知道每一個塊的左端點和右端點,維護一個左端點有序的隊列,進行二分尋找。也就是說沒New一個塊,那麼我們就向有序列中添加一個塊的左右斷電的節點;沒刪除一個塊,我們就將該點從序列中刪除。
這道題有點猥瑣,將一個塊的左右端點放線上段樹內維護要T,不知道是我寫搓了還是本來就卡這個時限。
如果有不明白還是看看My Code吧:
#include <iostream>#include <cstring>#include <cstdio>#include <cstdlib>#include <vector>#define MAX 50100#define lson l,m,k<<1#define rson m+1,r,k<<1|1using namespace std;typedef struct SEG{ int dt; int lnum,mnum,rnum;}Seg;Seg seg[MAX<<2];void PushUp(int l,int r,int k){ if(seg[k<<1].dt==seg[k<<1|1].dt) seg[k].dt=seg[k<<1].dt; else seg[k].dt=-1; int m = (l+r)>>1; if(seg[k<<1].lnum==(m-l+1)) seg[k].lnum=seg[k<<1].lnum+seg[k<<1|1].lnum; else seg[k].lnum=seg[k<<1].lnum; if(seg[k<<1|1].rnum==(r-m)) seg[k].rnum=seg[k<<1|1].rnum+seg[k<<1].rnum; else seg[k].rnum=seg[k<<1|1].rnum; seg[k].mnum=max(seg[k<<1].rnum+seg[k<<1|1].lnum,max(seg[k<<1].mnum,seg[k<<1|1].mnum)); seg[k].mnum=max(seg[k].mnum,max(seg[k].lnum,seg[k].rnum));}void PushDown(int l,int r,int k){ if(seg[k].dt>-1) { int m = (l+r)>>1; if(seg[k].dt==0) { seg[k<<1].dt=0; seg[k<<1].lnum=seg[k<<1].mnum=seg[k<<1].rnum=m-l+1; seg[k<<1|1].dt=0; seg[k<<1|1].lnum=seg[k<<1|1].mnum=seg[k<<1|1].rnum=r-m; } else { seg[k<<1].dt=seg[k<<1|1].dt=seg[k].dt; seg[k<<1].lnum=seg[k<<1].mnum=seg[k<<1].rnum=0; seg[k<<1|1].lnum=seg[k<<1|1].mnum=seg[k<<1|1].rnum=0; } seg[k].dt=-1; }}void Init(int l,int r,int k){ seg[k].dt=0; if(l==r) { seg[k].lnum=seg[k].rnum=seg[k].mnum=1; return ; } int m = (l+r)>>1; Init(lson); Init(rson); PushUp(l,r,k);}void Update(int ll,int rr,int v,int l,int r,int k){ if(ll==l&&rr==r) { seg[k].dt=v; if(v==0) { seg[k].lnum=seg[k].mnum=seg[k].rnum=r-l+1; } else { seg[k].lnum=seg[k].mnum=seg[k].rnum=0; } return ; } PushDown(l,r,k); int m = (l+r)>>1; if(rr<=m) Update(ll,rr,v,lson); else if(ll>m) Update(ll,rr,v,rson); else { Update(ll,m,v,lson); Update(m+1,rr,v,rson); } PushUp(l,r,k);}int Query(int x,int l,int r,int k)//尋找連續的x個0{ if(seg[k].mnum<x) return 0; int m = (l+r)>>1; if(seg[k].lnum>=x) return l; PushDown(l,r,k); int ans; if(seg[k<<1].mnum>=x) ans = Query(x,lson); else if(seg[k<<1].rnum+seg[k<<1|1].lnum>=x) ans = m-seg[k<<1].rnum+1; else ans = Query(x,rson); PushUp(l,r,k); return ans;}typedef struct NODE{ int l,r;}Node;vector<Node> myList;int Find(int x){ int l = 0; int r = myList.size()-1; while(l<=r) { int mid = (l+r)>>1; if(x>=myList[mid].l) l = mid+1; else r = mid-1; } return l;}int main(){ int n,m; int a,b; char op[20]; while(scanf("%d%d",&n,&m)!=EOF) { Init(1,n,1); myList.clear(); while(m--) { scanf("%s",op); if(strcmp(op,"Reset")!=0) scanf("%d",&a); if(strcmp(op,"New")==0) { int ans = Query(a,1,n,1); if(ans==0) printf("Reject New\n"); else { Update(ans,ans+a-1,1,1,n,1); Node t ; t.l=ans,t.r=ans+a-1; int x = Find(t.l); myList.insert(myList.begin()+x,t); printf("New at %d\n",ans); } } else if(strcmp(op,"Free")==0) { int t = Find(a); --t; if(t>-1&&myList[t].r>=a) { printf("Free from %d to %d\n",myList[t].l,myList[t].r); Update(myList[t].l,myList[t].r,0,1,n,1); myList.erase(myList.begin()+t); } else { printf("Reject Free\n"); } } else if(strcmp(op,"Get")==0) { int len = myList.size(); --a; if(a>=len) printf("Reject Get\n"); else { printf("Get at %d\n",myList[a].l); } } else { Update(1,n,0,1,n,1); myList.clear(); printf("Reset Now\n"); } } printf("\n"); } return 0;}