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|1 using 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,不知道是我写搓了还是本来就卡这个时限。
如果有不明白还是看看我的代码吧:
#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|1 using 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; }