Sample Input
3 1
1 2 3
1 1
Sample Output
Case 1:
1 1
线段树
L,R表示该区间的左右端点,sum表示该区间值的总和
l,r表示该区间连续的最大和的左右端点,maxall表示该区间的连续最大和
maxqj表示该区间的前缀连续最大和(即val[L]必取),qj表示该区间的前缀连续最大和右端点
maxhj表示该区间的后缀连续最大和(即val[R]必取),hj表示该区间的前缀连续最大和左端点
更新maxall:分3类讨论
1.连续最大和在左子树 或 几种情况中连续最大和相等且这种情况的连续最大和的左端点较小或相等
取左子树的连续最大和及端点
2.连续最大和在左右两子树 或 几种情况中连续最大和相等且这种情况的连续最大和的左端点较小
取左子树的后缀连续最大和加右子树的前缀连续最大和
3.连续最大和在右子树
取有子树的连续最大和及端点
更新maxqj:分两类讨论
1.前缀连续最大和在左右两子树
取左子树的区间值的总和加右子树的前缀连续最大和及端点
2.前缀连续最大和在左子树 或 几种情况中前缀连续最大和相等
取左子树的前缀连续最大和及端点
更新maxhj:分两类讨论
1.后缀连续最大和在左右两子树 或 几种情况中后缀连续最大和相等
取右子树的区间值的总和加左子树的后缀连续最大和及端点
2.后缀连续最大和在右子树
取右子树的后缀连续最大和及端点
更新sum:把左右两子树的sum加起来
对于[a,b],我们用分治的思想,分三种情况讨论:
1.[a,b]在左子树,对左子树递归调用
2.[a,b]在右子树,对右子树递归调用
3.[a,b]在左右子树,对[a,mid],[mid+1,b]分别递归调用
t1(结构体)表示左子树返回的东西,t2表示右子树返回的东西,t表示该子树返回的东西
很明显,对于t的更新,和上面对tree的更新一模一样
如果当前区间与线段树中某区间重合,直接返回线段树中该区间存的内容即可
记得long long
#include<iostream> #include<cstdio> using namespace std; typedef long long ll; int val[500001],n,m; struct xxx{ int L,R; int l,r,qj,hj; ll sum,maxqj,maxhj,maxall; }tree[2000001]; inline int read(){ int x;bool f;char c; for (f=0; (c=getchar())<'0'||c>'9'; f=c=='-'); for (x=c-'0'; (c=getchar())>='0'&&c<='9'; x=(x<<3)+(x<<1)+c-'0'); return f?-x:x; } void pushup(int x) { ll x1=tree[x<<1].maxall,x2=tree[x<<1].maxhj+tree[x<<1|1].maxqj,x3=tree[x<<1|1].maxall; if(x1>=x3&&(x1>x2||x1==x2&&tree[x<<1].l<=tree[x<<1].hj)) tree[x].maxall=x1,tree[x].l=tree[x<<1].l,tree[x].r=tree[x<<1].r; else if(x2>=x3) tree[x].maxall=x2,tree[x].l=tree[x<<1].hj,tree[x].r=tree[x<<1|1].qj; else tree[x].maxall=x3,tree[x].l=tree[x<<1|1].l,tree[x].r=tree[x<<1|1].r; if(tree[x<<1].sum+tree[x<<1|1].maxqj>tree[x<<1].maxqj) tree[x].maxqj=tree[x<<1].sum+tree[x<<1|1].maxqj,tree[x].qj=tree[x<<1|1].qj; else tree[x].maxqj=tree[x<<1].maxqj,tree[x].qj=tree[x<<1].qj; if(tree[x<<1|1].sum+tree[x<<1].maxhj>=tree[x<<1|1].maxhj) tree[x].maxhj=tree[x<<1|1].sum+tree[x<<1].maxhj,tree[x].hj=tree[x<<1].hj; else tree[x].maxhj=tree[x<<1|1].maxhj,tree[x].hj=tree[x<<1|1].hj; tree[x].sum=tree[x<<1].sum+tree[x<<1|1].sum; } void build(int x,int l,int r) { if(l==r) { tree[x].sum=tree[x].maxqj=tree[x].maxhj=tree[x].maxall=(ll)val[l]; tree[x].l=tree[x].r=tree[x].qj=tree[x].hj=tree[x].L=tree[x].R=l;return; } tree[x].L=l;tree[x].R=r; int mid=(l+r)>>1; build(x<<1,l,mid);build(x<<1|1,mid+1,r);pushup(x); //cout<<l<<" "<<r<<" "<<tree[x].maxall<<" "<<tree[x].l<<" "<<tree[x].r<<tree[x].hj<<endl; } xxx query(int x,int l,int r) { if(l==tree[x].L&&r==tree[x].R)return tree[x]; int mid=(tree[x].L+tree[x].R)/2; if(r<=mid)return query(x<<1,l,r); else if(l>mid)return query(x<<1|1,l,r); else { xxx t1=query(x<<1,l,mid),t2=query(x<<1|1,mid+1,r),t; ll x1=t1.maxall,x2=t1.maxhj+t2.maxqj,x3=t2.maxall; if(x1>=x3&&(x1>x2||x1==x2&&t1.l<=t1.hj)) t.maxall=x1,t.l=t1.l,t.r=t1.r; else if(x2>=x3) t.maxall=x2,t.l=t1.hj,t.r=t2.qj; else t.maxall=x3,t.l=t2.l,t.r=t2.r; if(t1.sum+t2.maxqj>t1.maxqj) t.maxqj=t1.sum+t2.maxqj,t.qj=t2.qj; else t.maxqj=t1.maxqj,t.qj=t1.qj; if(t2.sum+t1.maxhj>=t2.maxhj) t.maxhj=t2.sum+t1.maxhj,t.hj=t1.hj; else t.maxhj=t2.maxhj,t.hj=t2.hj; return t; } } int main() { int T=0; while(~scanf("%d%d",&n,&m)) { T++; for(int i=1;i<=n;i++)val[i]=read(); build(1,1,n); printf("Case %d: ",T); for(int i=1;i<=m;i++) { int a=read(),b=read(); xxx x=query(1,a,b); printf("%d %d ",x.l,x.r); } } return 0; }