线段树 区间合并
来源:互联网 发布:中科软件集团有限公司 编辑:程序博客网 时间:2024/05/17 02:18
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,不知道是我写搓了还是本来就卡这个时限。
如果有不明白还是看看我的代码吧:
#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;}
- 线段树 区间合并
- 线段树 区间合并
- 线段树 区间合并
- 线段树 区间合并
- 线段树-区间合并
- 谈区间合并线段树
- hdu3308 线段树区间合并
- poj3667线段树区间合并
- poj3667 线段树+区间合并
- hdu3308 线段树 区间合并
- 线段树练习 区间合并
- poj3667(线段树区间合并)
- 线段树 (区间合并)
- 线段树区间合并poj3667
- hdu4351 线段树 区间合并
- hfutoj1300 线段树 区间合并
- 线段树之区间合并
- LCIS --线段树区间合并
- http://qqtornado.blog.sohu.com/
- 一万小时成功定律--2012年2月江西IDC排行榜
- android(3)
- JSP学习总结——jsp页面元素
- 11、求二叉树中节点的最大距离
- 线段树 区间合并
- 单链表
- ccsu1359 木棒相交 (叉积线段判交,并查集判断是否属于同一个集合)
- dede 序号 递增
- js实现图片上传预览
- Windows Phone 7开发之ToggleSwitch-兵乓开关
- 手机播放声音和震动
- 配置yum源【附脚本】
- POJ 1830 开关问题 高斯消元