题目描述 Description
|
||||||||
给一个长度为N的序列以及Q的询问,每次两个参数l,r,问你序列[l,r]中的最大连续和
|
||||||||
输入描述 Input Description
|
||||||||
一行二个正整数N,Q。 |
||||||||
输出描述 Output Description
|
||||||||
对于每个询问,输出一行一个整数,描述答案。
|
||||||||
样例输入 Sample Input
|
||||||||
4 3
1 -2 3 2 1 4 1 2 2 2 |
||||||||
样例输出 Sample Output
|
||||||||
5
1
0
|
||||||||
数据范围及提示 Data Size & Hint
|
||||||||
|
线段树。对于每个节点,维护三个值。sum,suml,sumr表示该点的最大连续和,最大前缀和和最大后缀和。
#include<iostream> #include<cmath> #include<cstring> #include<cstdio> #include<algorithm> #include<queue> using namespace std; typedef long long LL; inline int read() { int x=0,f=1;char c=getchar(); while(!isdigit(c)){if(c=='-')f=-1;c=getchar();} while(isdigit(c)){x=x*10+c-'0';c=getchar();} return x*f; } const int oo=2147000000; const int maxn=1000010; int n,q,a[maxn],x,y; LL pre[maxn],sum[maxn],suml[maxn],sumr[maxn]; void build(int l,int r,int o) { if(l==r) { suml[o]=sumr[o]=sum[o]=pre[r]-pre[l-1]; return; } int mid=(l+r)>>1,lo=o<<1,ro=lo+1; build(l,mid,lo); build(mid+1,r,ro); sum[o]=max(sum[lo],sum[ro]); sum[o]=max(sum[o],sumr[lo]+suml[ro]); suml[o]=max(suml[lo],pre[mid]-pre[l-1]+suml[ro]); sumr[o]=max(sumr[ro],pre[r]-pre[mid]+sumr[lo]); return; } LL queryl(int x,int y,int l,int r,int o) { if(x==l && y==r) return sumr[o]; int mid=(l+r)>>1,lo=o<<1,ro=lo+1; if(x>mid) return queryl(x,y,mid+1,r,ro); else { LL tmp=pre[r]-pre[mid]+queryl(x,mid,l,mid,lo); return max(sumr[ro],tmp); } } LL queryr(int x,int y,int l,int r,int o) { if(x==l && y==r) return suml[o]; int mid=(l+r)>>1,lo=o<<1,ro=lo+1; if(y<=mid) return queryr(x,y,l,mid,lo); else { LL tmp=pre[mid]-pre[l-1]+queryr(mid+1,y,mid+1,r,ro); return max(suml[lo],tmp); } } LL query(int x,int y,int l,int r,int o) { if(x<=l && y>=r)return sum[o]; int mid=(l+r)>>1,lo=o<<1,ro=lo+1; if(y<=mid) return query(x,y,l,mid,lo); else if(x>mid) return query(x,y,mid+1,r,ro); else { LL ls,rs; ls=queryl(x,mid,l,mid,lo); rs=queryr(mid+1,y,mid+1,r,ro); return max(max(query(x,mid,l,mid,lo),query(mid+1,y,mid+1,r,ro)),rs+ls); } } int main() { freopen("sequence.in","r",stdin); freopen("sequence.out","w",stdout); n=read();q=read(); for(int i=1;i<=n;i++)a[i]=read(),pre[i]=pre[i-1]+a[i]; build(1,n,1); while(q--) { x=read();y=read(); LL tmp=query(x,y,1,n,1); if(tmp<0)tmp=0; printf("%lld ",tmp); } return 0; }
对于后三个点肯定没戏,毕竟线段树常数那么大。满分做法好像是整体二分,然而并不会,等着以后来填坑吧。