【线段树】bzoj1756 Vijos1083 小白逛公园
2015-07-07 21:46
357 查看
我们知道,求一段序列的最大子段和是O(n)的,但是这样是显然会超时的。
我们需要一个数据结构来支持修改和计算的操作,对于这种修改一个而查询区间的问题,考虑使用线段树。
在线段树中,除了左端点,右端点,左儿子指针,右儿子指针之外,新开4个域——max,maxl,maxr,sum,其中sum为该区间的和,max为该区间上的最大子段和,maxl为必须包含左端点的最大子段和,maxr为必须包含右端点的最大子段和。
然后就……可以用线段树来统计了,注意求得的最大子段和中至少包含1个元素,所以出现了样例那样的输出负值。
修改时:
1、若左儿子的maxr和右儿子的maxl都为负,就从中取较大的为该节点的max(防止一个都不取),反之取二者中正的(都正就都取)。
2、将该节点的max用左右儿子的max更新。
3、该节点的maxl为左儿子的maxl与左儿子sum和右儿子maxl和的最大值。
4、该节点的maxr为右儿子的maxr与右儿子sum和左儿子maxr和的最大值。
5、该节点的sum为左右儿子的sum和。
查询时:
1、如果查询区间覆盖这一节点,将该节点信息返回。
2、如果只与一个儿子有交集,就返回在那个儿子中查找到的信息。
3、如果与两个儿子都有交集,就先分别计算出两个儿子的信息,然后按修改的方式将两个信息合并,然后返回。
4、最后返回的max值即为答案。
——http://www.cnblogs.com/whitecloth/archive/2012/03/22/2410925.html
我们需要一个数据结构来支持修改和计算的操作,对于这种修改一个而查询区间的问题,考虑使用线段树。
在线段树中,除了左端点,右端点,左儿子指针,右儿子指针之外,新开4个域——max,maxl,maxr,sum,其中sum为该区间的和,max为该区间上的最大子段和,maxl为必须包含左端点的最大子段和,maxr为必须包含右端点的最大子段和。
然后就……可以用线段树来统计了,注意求得的最大子段和中至少包含1个元素,所以出现了样例那样的输出负值。
修改时:
1、若左儿子的maxr和右儿子的maxl都为负,就从中取较大的为该节点的max(防止一个都不取),反之取二者中正的(都正就都取)。
2、将该节点的max用左右儿子的max更新。
3、该节点的maxl为左儿子的maxl与左儿子sum和右儿子maxl和的最大值。
4、该节点的maxr为右儿子的maxr与右儿子sum和左儿子maxr和的最大值。
5、该节点的sum为左右儿子的sum和。
查询时:
1、如果查询区间覆盖这一节点,将该节点信息返回。
2、如果只与一个儿子有交集,就返回在那个儿子中查找到的信息。
3、如果与两个儿子都有交集,就先分别计算出两个儿子的信息,然后按修改的方式将两个信息合并,然后返回。
4、最后返回的max值即为答案。
——http://www.cnblogs.com/whitecloth/archive/2012/03/22/2410925.html
#include<cstdio> #include<algorithm> using namespace std; #define N 500001 struct Node{int maxv,maxl,maxr,sumv;}T[N<<2]; inline void pushup(Node &rt,const Node &ls,const Node &rs) { if(ls.maxr<0 && rs.maxl<0) rt.maxv=max(ls.maxr,rs.maxl); else { rt.maxv=0; if(ls.maxr>0) rt.maxv+=ls.maxr; if(rs.maxl>0) rt.maxv+=rs.maxl; } rt.maxv=max(rt.maxv,ls.maxv); rt.maxv=max(rt.maxv,rs.maxv); rt.maxl=max(ls.maxl,ls.sumv+rs.maxl); rt.maxr=max(rs.maxr,rs.sumv+ls.maxr); rt.sumv=ls.sumv+rs.sumv; } void buildtree(int rt,int l,int r) { if(l==r) { scanf("%d",&T[rt].maxv); T[rt].sumv=T[rt].maxl=T[rt].maxr=T[rt].maxv; return; } int m=(l+r>>1); buildtree(rt<<1,l,m); buildtree(rt<<1|1,m+1,r); pushup(T[rt],T[rt<<1],T[rt<<1|1]); } void update(int p,int v,int rt,int l,int r) { if(l==r) { T[rt].sumv=T[rt].maxl=T[rt].maxr=T[rt].maxv=v; return; } int m=(l+r>>1); if(p<=m) update(p,v,rt<<1,l,m); else update(p,v,rt<<1|1,m+1,r); pushup(T[rt],T[rt<<1],T[rt<<1|1]); } Node query(int ql,int qr,int rt,int l,int r) { if(ql<=l&&r<=qr) return T[rt]; int m=(l+r>>1); if(ql<=m && m<qr) { Node res; pushup(res,query(ql,qr,rt<<1,l,m),query(ql,qr,rt<<1|1,m+1,r)); return res; } else if(ql<=m) return query(ql,qr,rt<<1,l,m); else return query(ql,qr,rt<<1|1,m+1,r); } int n,m; int main() { int op,x,y; scanf("%d%d",&n,&m); buildtree(1,1,n); for(;m;--m) { scanf("%d%d%d",&op,&x,&y); if(op==1) { if(x>y) swap(x,y); printf("%d\n",query(x,y,1,1,n).maxv); } else update(x,y,1,1,n); } return 0; }
相关文章推荐
- java学习12--函数--练习
- poj 3361 Gaussian Prime Factors 高斯素数约数
- poj 3361 Gaussian Prime Factors 高斯素数约数
- Ubuntu环境下安装jdk
- 字典 或者 模型 加不进数组
- 机器学习算法与Python实践之(二)支持向量机(SVM)初级
- 七月六号
- ScheduledThreadPoolExecutor定时使用
- unity3d中的动画
- 关于如何简单创建Xml文件和用SAX解析
- 整理阅读的论文(三)
- tabBar 的显示
- 七月三号
- jQuery基础入门第一弹
- Linux socket关闭连接shutdown与close
- mini2440第一课《汇编点亮LED》
- 78.对学生成绩进行排序
- [一车大师]微信运营心得
- 【LeetCode】232. Implement Queue using Stacks
- android反射组件 (一个)java 它们的定义annotation基础知识