SPOJ 1043 Can you answer these queries I (超强线段树)
2017-07-18 13:02
453 查看
GSS1 - Can you answer these queries I
[align=center]#tree[/align]You are given a sequence A[1], A[2], ..., A
. ( |A[i]| ≤ 15007 , 1 ≤ N ≤ 50000 ). A query is defined as follows:
Query(x,y) = Max { a[i]+a[i+1]+...+a[j] ; x ≤ i ≤ j ≤ y }.
Given M queries, your program must output the results of these queries.
Input
The first line of the input file contains the integer N.In the second line, N numbers follow.
The third line contains the integer M.
M lines follow, where line i contains 2 numbers xi and yi.
Output
Your program should output the results of the M queries, one query per line.Example
Input: 3 -1 2 3 1 1 2 Output: 2
题意简单明了,静态求区间最大连续子序列。
想起之前做过的一道LCT的题目,是求链上染色区域个数,和这个有丝丝相似。
首先,通过观察区间最大连续子序列和的构成,我们发现,某一个区间的最大连续子序列max的备选序列可以是它的左右子区间的最大连续子序列,或者是左子区间的最大右端连续子序列rmax与右子区间的最大左端连续子序列lmax的和。那么在一棵线段树中,我们需要维护的就是该区间的最大连续子序列max、最大左端连续子序列lmax和最大右端连续子序列rmax。
维护max,刚刚已经说了,那么lmax和rmax如何维护呢。这个我也是错了几次后才弄懂的。首先,显然的lmax可以是继承它左子区间的lmax,但是如果说右子区间的lmax很大,那会不会影响总区间的lmax呢?答案是肯定的。对于lmax,它的大小是左子区间的lmax 与 左子区间和+右子区间lmax 中大的那个。即左端最大连续子区间可以是左子区间的lmax,也可以是整个左子区间的和加上有自取件的lmax。简单的例子就是:-1,2。区间[1,1]的lmax=-1,则区间[1,2]的lmax应该等于2-1=1,而不是-1。同理,右端连续最大也是这样维护的。这也就意味着我们还有维护一个区间和sum,这个就是非常基础的线段树操作了,在这里不再赘述。
还有一个比较麻烦的地方就是查询了。即使写好了维护,查询也不是那么好理解的。因为查询的区间可能横跨两个子区间,这个时候又要仔细考虑了。同样,它可以是两个子区间中max大的那个,还可以是左子区间的rmax+右子区间的lmax,而要求这个lmax和rmax,则又要写两个函数去计算。然后在getlmax和getrmax的时候,要点和维护lmax和rmax的时候一样,返回的最优解可能也会跨一个子区间,所以说我们还要写一个getsum的函数计算区间总和。真够麻烦的,具体见代码:
#include<bits/stdc++.h> #define LL long long #define N 201000 using namespace std; struct ST { LL a ; struct node { LL lmax,rmax,max,sum,num; int l,r; } tree[N*4]; inline void push_up(int i) { tree[i].sum=tree[i<<1].sum+tree[i<<1|1].sum; tree[i].max=max(tree[i<<1].max,tree[i<<1|1].max); //max是三个备选解中大的那个 tree[i].max=max(tree[i].max,tree[i<<1].rmax+tree[i<<1|1].lmax); tree[i].lmax=max(tree[i<<1].lmax,tree[i<<1].sum+tree[i<<1|1].lmax); //lmax、rmax要跨区间比较 tree[i].rmax=max(tree[i<<1|1].rmax,tree[i<<1|1].sum+tree[i<<1].rmax); } inline void build(int i,int l,int r) { tree[i].r=r; tree[i].l=l; if (l==r) { tree[i].num=tree[i].rmax=a[l]; tree[i].lmax=tree[i].max=a[l]; tree[i].sum=a[l]; return; } LL mid=(l+r)>>1; build(i<<1,l,mid); build(i<<1|1,mid+1,r); push_up(i); } inline LL getsum(int i,int l,int r) //计算区间和 { if ((tree[i].l==l)&&(tree[i].r==r)) return tree[i].sum; LL mid=(tree[i].l+tree[i].r)>>1; if (mid>=r) return getsum(i<<1,l,r); else if (mid<l) return getsum(i<<1|1,l,r); else return getsum(i<<1,l,mid)+getsum(i<<1|1,mid+1,r); } inline LL getrmax(int i,int l,int r) //计算右端最大连续子序列 { if ((tree[i].l==l)&&(tree[i].r==r)) return tree[i].rmax; LL mid=(tree[i].l+tree[i].r)>>1; if (mid>=r) return getrmax(i<<1,l,r); else if (mid<l) return getrmax(i<<1|1,l,r); else return max(getrmax(i<<1|1,mid+1,r),getrmax(i<<1,l,mid)+getsum(i<<1|1,mid+1,r)); //解可能跨区间 } inline LL getlmax(int i,int l,int r) //计算左端最大连续子序列 { if ((tree[i].l==l)&&(tree[i].r==r)) return tree[i].lmax; LL mid=(tree[i].l+tree[i].r)>>1; if (mid>=r) return getlmax(i<<1,l,r); else if (mid<l) return getlmax(i<<1|1,l,r); else return max(getlmax(i<<1,l,mid),getlmax(i<<1|1,mid+1,r)+getsum(i<<1,l,mid)); //解可能跨区间 } inline LL getmax(int i,int l,int r) //计算区间最大子序列 { if ((tree[i].l==l)&&(tree[i].r==r)) return tree[i].max; LL mid=(tree[i].l+tree[i].r)>>1; if (mid>=r) return getmax(i<<1,l,r); else if (mid<l) return getmax(i<<1|1,l,r); else { LL a=max(getmax(i<<1,l,mid),getmax(i<<1|1,mid+1,r)); LL b=getrmax(i<<1,l,mid)+getlmax(i<<1|1,mid+1,r); return max(a,b); //解可能是两个子区间值大的那个也可能是中间部分 } } } seg; int n; int main() { while(~scanf("%d",&n)) { memset(seg.a,0,sizeof(seg.a)); for(int i=1;i<=n;i++) scanf("%lld",&seg.a[i]); seg.build(1,1,n); int q; cin>>q; while(q--) { int x,y; scanf("%d%d",&x,&y); printf("%lld\n",seg.getmax(1,x,y)); } } return 0; }
相关文章推荐
- spoj 1043. Can you answer these queries I (线段树)
- 【线段树】 SPOJ 1043 Can you answer these queries I 区间合并
- 【线段树】 SPOJ 1043 Can you answer these queries I 区间合并
- SPOJ 1043 Can you answer these queries I 求任意区间最大连续子段和 线段树
- 【SPOJ】 1043 Can you answer these queries I 线段树
- SPOJ 1043 Can you answer these queries I(GSS1 线段树)
- spoj 1043 Can you answer these queries I(线段树)
- SPOJ 1557 Can you answer these queries II(GSS2 线段树)
- SPOJ GSS3 Can you answer these queries III ——线段树
- 线段树【SP1043】GSS1 - Can you answer these queries I
- SPOJ 1043 1043. Can you answer these queries I
- spoj 2916. Can you answer these queries V(线段树)
- 数据结构(线段树):SPOJ GSS3 - Can you answer these queries III
- SPOJ 1716 Can you answer these queries III(GSS3 线段树)
- GSS5 spoj 2916. Can you answer these queries V 线段树
- 【SPOJ-GSS1】Can you answer these queries I【线段树】【最大子段和】
- SPOJ GSS3 Can you answer these queries III(线段树)
- SPOJ GSS5 Can you answer these queries V ——线段树
- SPOJ GSS1_Can you answer these queries I(线段树区间合并)
- SPOJ 1043 1043. Can you answer these queries I