3981 动态最大子段和
Posted whymhe
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了3981 动态最大子段和相关的知识,希望对你有一定的参考价值。
题目描述 Description
题目还是简单一点好...
有n个数,a[1]到a[n]。
接下来q次查询,每次动态指定两个数l,r,求a[l]到a[r]的最大子段和。
子段的意思是连续非空区间。
输入描述 Input Description
第一行一个数n。
第二行n个数a[1]~a[n]。
第三行一个数q。
以下q行每行两个数l和r。
输出描述 Output Description
q行,每行一个数,表示a[l]到a[r]的最大子段和。
样例输入 Sample Input
7
2 3 -233 233 -23 -2 233
4
1 7
5 6
2 5
2 3
样例输出 Sample Output
441
-2
233
3
数据范围及提示 Data Size & Hint
对于50%的数据,q*n<=10000000。
对于100%的数据,1<=n<=200000,1<=q<=200000。
a[1]~a[n]在int范围内,但是答案可能超出int范围。
数据保证1<=l<=r<=n。
空间128M,时间1s。
我不会告诉你数据里有样例
//题意:询问一段区间的最大子序列的值。 //就是GSS1多开点空间然后开longlong //做法:维护四个值:包含当前区间左端点的最大子区间LM,包含当前区间右端点的最大子区间RM、当前区间的最大子区间M, 当前区间的区间和S //tree[root].maxn=max(tree[root<<1].maxn,max(tree[root<<1|1].maxn,tree[root<<1].rmaxn+tree[root<<1|1].lmaxn)); // tree[root].lmaxn=max(tree[root<<1].lmaxn,tree[root<<1].sum+tree[root<<1|1].lmaxn); // tree[root].rmaxn=max(tree[root<<1|1].rmaxn,tree[root<<1|1].sum+tree[root<<1].rmaxn); // tree[root].sum=tree[root<<1].sum+tree[root<<1|1].sum; #include<iostream> #include<cstdio> #include<cstring> #include<cmath> #include<algorithm> using namespace std; const int N=2e5+5; int n,m,l,r; long long L,R,M,S; struct Tree { int l,r,mid; long long sum,lmaxn,rmaxn,maxn; }tree[N<<2]; inline long long read() { char c=getchar();long long num=0,f=1; for(;!isdigit(c);c=getchar()) f=c==‘-‘?-1:f; for(;isdigit(c);c=getchar()) num=num*10+c-‘0‘; return num*f; } inline void pushup(int root) { tree[root].maxn=max(tree[root<<1].maxn,max(tree[root<<1|1].maxn,tree[root<<1].rmaxn+tree[root<<1|1].lmaxn)); tree[root].lmaxn=max(tree[root<<1].lmaxn,tree[root<<1].sum+tree[root<<1|1].lmaxn); tree[root].rmaxn=max(tree[root<<1|1].rmaxn,tree[root<<1|1].sum+tree[root<<1].rmaxn); tree[root].sum=tree[root<<1].sum+tree[root<<1|1].sum; } void build(int root,int l,int r) { tree[root].l=l,tree[root].r=r,tree[root].mid=l+r>>1; if(l==r) { tree[root].sum=tree[root].maxn=tree[root].rmaxn=tree[root].lmaxn=read(); return; } build(root<<1,l,tree[root].mid); build(root<<1|1,tree[root].mid+1,r); pushup(root); } void query(int root,int l,int r,long long &L,long long &R,long long &M,long long &S) { if(l<=tree[root].l&&tree[root].r<=r) { L=tree[root].lmaxn, R=tree[root].rmaxn, M=tree[root].maxn, S=tree[root].sum; return; } if(tree[root].mid>=r) { query(root<<1,l,r,L,R,M,S); } else if(tree[root].mid<l) { query(root<<1|1,l,r,L,R,M,S); } else { long long lL=0,lR=0,lM=0,lS=0,rL=0,rR=0,rM=0,rS=0; query(root<<1,l,tree[root].mid,lL,lR,lM,lS); query(root<<1|1,tree[root].mid+1,r,rL,rR,rM,rS); L=max(lL,lS+rL); R=max(rR,rS+lR); M=max(lR+rL,max(lM,rM)); S=lS+rS; } } int main() { n=read(); build(1,1,n); m=read(); for(int i=1;i<=m;++i) { l=read(),r=read(); query(1,l,r,L,R,M,S); printf("%lld\n",M); } return 0; }
以上是关于3981 动态最大子段和的主要内容,如果未能解决你的问题,请参考以下文章