kb-09-线段树--区间合并比较繁
2015-05-31 23:01
239 查看
/* hdu-1540 题意:一个线段,长度为n,三种操作,Dx,挖掉某个点;R,恢复最近被挖掉的点;Qx查询该点所在的连续区间的长度; 树的节点维护三个变量,该节点左边界开始连续的个数ll,右边界开始向左连续的个数rl,(在该区间内),该区间内最大的连续区间的长度ml; 最后一个变量是为了方便判断,主要的还是前两个; 修改的时候先是深入单点修改单点信息,然后回溯上来更父结点,更新的时候有点复杂; 查询的时候借助ml的长度减少计算量,快速返回; 区间合并; */ #include<cstdio> #include<iostream> #include<cstring> #include<stack> #include<algorithm> using namespace std; struct Node { int l,r,ll,rl,ml; }tr[200005]; void build(int rt,int l,int r) { tr[rt].l=l; tr[rt].r=r; tr[rt].ll=tr[rt].rl=tr[rt].ml=r-l+1; if(l==r) return ; int mid=(l+r)/2; build(rt<<1,l,mid); build(rt<<1|1,mid+1,r); } void Update(int rt,int l,int r,int t,int val)//t是要改的点; { if(l==r) //找到单点; { if(val==1) { tr[rt].ll=tr[rt].rl=tr[rt].ml=1;//改单点的信息; } else { tr[rt].ll=tr[rt].rl=tr[rt].ml=0; } return ; } int mid=(l+r)/2;//二分查找区间; if(t<=mid) { Update(rt<<1,l,mid,t,val); } else { Update(rt<<1|1,mid+1,r,t,val); } // pushup操作; tr[rt].ll=tr[rt<<1].ll; //左子树的左侧边界的值给父节点; tr[rt].rl=tr[rt<<1|1].rl; //右子树的有边界的值给父结点; tr[rt].ml=max(tr[rt<<1].ml,tr[rt<<1|1].ml); //左右子树的最大连续数; tr[rt].ml=max(tr[rt].ml,tr[rt<<1].rl+tr[rt<<1|1].ll); //两个子树的交接处的最大连续数; if(tr[rt<<1].ll==mid-l+1) tr[rt].ll+=tr[rt<<1|1].ll; //如果左子树是全连续的,就更新父节点的左边界最大连续数; if(tr[rt<<1|1].rl==r-mid) //如果右子树是连续的,就更新父结点的有边界的最大连续数; tr[rt].rl+=tr[rt<<1].rl; } int Query(int rt,int l,int r,int t)//查询与这个点连接的最长序列; { if(l==r||tr[rt].ml==0||tr[rt].ml==r-l+1) //如果找到单点,或该区间全空,或该区间全满;就返回; return tr[rt].ml; int mid=(l+r)/2; if(t<=mid) //如果该点在左子树上 { if(t>=tr[rt<<1].r-tr[rt<<1].rl+1) //如果该点是在左子树右边界点连续范围,就进入左子树继续搜索该点并加上搜索右子树的左边界那个点的结果; return Query(rt<<1,l,mid,t)+Query((rt<<1)|1,mid+1,r,mid+1); else return Query(rt<<1,l,mid,t); //如果不再右连续块内就进左子树继续搜索; } else//右子树; { if(t<=tr[rt<<1|1].l+tr[rt<<1|1].ll-1) //在右子树的左侧连续的部分内,就加上左子树上的数据,左子树右边界的(不能用有子树的数据因为那不是全部的数据); return Query(rt<<1|1,mid+1,r,t)+Query(rt<<1,l,mid,mid); else return Query(rt<<1|1,mid+1,r,t); } } int main() { int n,m; while(scanf("%d%d",&n,&m)!=EOF&&n&&m) { memset(tr,0,sizeof(tr)); stack<int > z; build(1,1,n); for(int i=0;i<m;i++) { char a[3]; scanf("%s",a); if(a[0]=='D') { int x; scanf("%d",&x); z.push(x); Update(1,1,n,x,0); //0代表删除操作; } else if(a[0]=='R') { if(!z.empty()) { int x=z.top(); z.pop(); Update(1,1,n,x,1); //1代表回复操作; } } else if(a[0]=='Q') { int x; scanf("%d",&x); int ans=Query(1,1,n,x); printf("%d\n",ans); } } } return 0; }
相关文章推荐
- j-link + gdb 2440裸机
- 纪念逝去的岁月——C++实现一个栈
- Intersection of Two Linked Lists | LeetCode
- 第十一周 项目3 - 点类派生直线类】定义点类Point,并以点类为基类,继承关系
- Qt网络编程
- Jsonp post 跨域方案
- iOS app 发布流程记录
- sql 中Group By的使用
- perl 获取更新部分日志
- 2015年5月做题记录
- 【转】erlang四种监控策略one_for_one、one_for_all、simple_one_for_one、rest_for_one
- socket中select针对阻塞I/O复用注意的问题
- 十分钟学习Python的进阶语法
- 网络爬虫Scrapy
- C# ICSharpCode.SharpZipLib.dll文件压缩和解压功能类整理,上传文件或下载文件很常用
- 5月26日作业
- DELL服务器装2003系统
- 网站导航如何优化
- 【数据结构】用C++编写队列及基本操作(包括插入,出队列,摧毁,清空等等)
- PyQt