SPOJ GSS1 Can you answer these queries I (线段树求区间最大连续和)
来源:互联网 发布:破解软件网盘 编辑:程序博客网 时间:2024/05/16 09:11
题目大意
给定一个数列,并给出一些询问的区间,求出询问区间内的最大连续区间和。
解题思路
直接上线段树,但是区间合并的时候遇到了一些困难。
首先我们考虑,想要达到 logn 级别的访问时间,对于线段树的每个节点中必须保存有该节点所表示区间内的最大连续区间和 mmax 。
然后我们考虑区间合并时最大值的取值情况:
1、等于左子结点中的区间最大值。
2、等于右子结点中的区间最大值。
3、最大连续区间横跨左子区间和右子区间。
在情况(1,2)和情况 3 取最大值的时候会遇到一些问题, 所以对于每个结点我们需要引入新的变量来存储更多的信息:
1、sum 表示该结点区间和。
2、suml 表示该结点包含最左端元素的最大连续区间和。
3、sumr 表示该结点包含最右端元素的最大连续区间和。
因此可得 mmax 的递推方程为
p[root].mmax=max(max(p[root<<1].mmax,p[root<<1|1].mmax),(p[root<<1].sumr+p[root<<1|1].suml));(root为当前的根节点)
suml 和 sumr 的递推方程为
p[root].suml=max(p[root<<1].suml,p[root<<1].sum+p[root<<1|1].suml);
p[root].sumr=max(p[root<<1|1].sumr,p[root<<1].sumr+p[root<<1|1].sum);
查询过程:
定义查询区间为 [ l , r ] , mid 为结点区间 [ left , right ] 中点
1、若查询区间位于 mid 左,则返回左子区间的查询结果。
2、若查询区间位于 mid 右,则返回右子区间的查询结果。
3、横跨左右子区间,则分别查询 [ l , mid ] 和 [ mid+1 , r ] 后按照上述规则合并。
附上代码
#include <cstdio>#include <cstring>#include <algorithm>#define MAX 50000+50using namespace std;int num[MAX];struct node{ int left,right; int mmax,sum,suml,sumr;}p[MAX<<2];int a[MAX];void build(int id,int l,int r){ p[id].left=l; p[id].right=r; if(l==r) { p[id].sum=a[l]; p[id].mmax=a[l]; p[id].suml=a[l]; p[id].sumr=a[l]; } else { int mid=(l+r)/2; build(2*id,l,mid); build(2*id+1,mid+1,r); p[id].sum=p[2*id].sum+p[2*id+1].sum; p[id].mmax=max(max(p[2*id].mmax,p[2*id+1].mmax),(p[2*id].sumr+p[2*id+1].suml)); p[id].suml=max(p[2*id].suml,p[2*id].sum+p[2*id+1].suml); p[id].sumr=max(p[2*id+1].sumr,p[2*id].sumr+p[2*id+1].sum); }}node query_sum(int id,int l,int r){ if(p[id].left==l&&p[id].right==r) return p[id]; else { node tmp,k1,k2; int mid=(p[id].left+p[id].right)/2; if(r<=mid) return query_sum(2*id,l,r); if(l>mid) return query_sum(2*id+1,l,r); k1=query_sum(2*id,l,mid); k2=query_sum(2*id+1,mid+1,r); tmp.sum=k1.sum+k2.sum; tmp.suml=max(k1.suml,k1.sum+k2.suml); tmp.sumr=max(k2.sumr,k1.sumr+k2.sum); tmp.mmax=max(max(k1.mmax,k2.mmax),k1.sumr+k2.suml); return tmp; }}int main(){ int n,q; while(~scanf("%d",&n)){ for(int i=1;i<=n;i++) scanf("%d",&a[i]); build(1,1,n); scanf("%d",&q); while(q--){ int left,right; scanf("%d%d",&left,&right); node ans=query_sum(1,left,right); printf("%d\n",ans.mmax); } } return 0;}
0 0
- SPOJ GSS1 Can you answer these queries I (线段树求区间最大连续和)
- 【SPOJ-GSS1】Can you answer these queries I【线段树】【最大子段和】
- SPOJ 1043 Can you answer these queries I 求任意区间最大连续子段和 线段树
- [SPOJ GSS1] Can you answer these queries I [线段树]
- GSS1 - Can you answer these queries I(动态查询区间最大连续和)
- SPOJ 1043 Can you answer these queries I(GSS1 线段树)
- SPOJ GSS1 - Can you answer these queries I(线段树维护GSS)
- Spoj 1716 Can you answer these queries III 线段树 单点修改 区间求最大子段和
- Spoj 2916 Can you answer these queries V 线段树 求任意重叠区间的最大子段和
- SPOJ GSS1 Can you answer these queries I
- SPOJ GSS1 Can you answer these queries I
- SPOJ GSS1 Can you answer these queries I
- SPOJ GSS1 Can you answer these queries I
- SPOJ GSS1 Can you answer these queries I
- SPOJ GSS1 Can you answer these queries I
- SPOJ GSS1 Can you answer these queries I
- spoj(GSS3) 1716 Can you answer these queries III(线段树求最大子段和)
- SPOJ GSS1 Can you answer these queries I(区间合并)
- 限时交易(可以跨天设置)
- 189_IO流_FileReader_文件字符输入流_详解
- OSI七层模型自我见解(第二次回顾修改红色标记)
- jstack和线程dump分析
- mysql中复制表结构的方法(亲测通过)
- SPOJ GSS1 Can you answer these queries I (线段树求区间最大连续和)
- 一、顺序表
- Problem A: STL——邮票
- Java线程Dump分析工具
- 分解质因数
- UOJ 109 [APIO2013]TASKSAUTHOR
- Github搜索技巧-如何使用github找到自己感兴趣的项目
- mvc webapi路由重写
- OpenGL学习笔记(二)