p1115 最大子段和(線段樹)
阿新 • • 發佈:2018-09-22
-a pri span 合並 大連 char using .org n)
題目描述-->p1115 最大子段和
雖然是一個普及-的題,但我敲了線段樹 qwq
數組定義
\(lsum[ ]\)代表 該區間左端點開始的最大連續和.
\(rsum[ ]\)代表 該區間右端點開始的最大連續和.
\(ssum[ ]\)代表 區間內最大連續和.
\(sum[ ]\) 代表區間和.
Que and A
Q:已知一個區間的左右區間的最大連續和,如何合並?
A:這個區間的最大連續和要麽是左子區間的最大連續和,要麽是右子區間的最大連續和.
要麽是左子區間的最大右起子段和+右子區間的最大左起字段和.
code
:\(ssum[o]=max(max(ssum[lson],ssum[rson]),rsum[lson]+lsum[rson])\)
Q:如何更新區間最大左起子段和.
A:新區間的最大左起子段和.要麽是其左子區間最大連續和,要麽是其左子區間和+右子區間的左起子段和.
最大右起子段和同理
code
:\(lsum[o]=max(lsum[lson],sum[lson]+lsum[rson])\)
\(rsum[o]=max(rsum[rson],sum[rson]+rsum[lson])\)
更新操作類似單點修改
貼一下代碼 qwq.
#include<bits/stdc++.h> #define IL inline #define int long long #define RI register int #define N 200008 #define ls o<<1 #define rs o<<1|1 using namespace std; IL void in(int &x) { int f=1;x=0;char s=getchar(); while(s>'9' or s<'0'){if(s=='-')f=-1;s=getchar();} while(s>='0' and s<='9'){x=x*10+s-'0';s=getchar();} x*=f; } int tr[N<<2],ssum[N<<2],lsum[N<<2],rsum[N<<2],n; IL void up(int o) { tr[o]=tr[ls]+tr[rs]; ssum[o]=max(max(ssum[ls],ssum[rs]),rsum[ls]+lsum[rs]); lsum[o]=max(lsum[ls],tr[ls]+lsum[rs]); rsum[o]=max(rsum[rs],tr[rs]+rsum[ls]); } IL void build(int o,int l,int r) { if(l==r) { in(tr[o]); ssum[o]=lsum[o]=rsum[o]=tr[o]; return; } int mid=(l+r)>>1; build(ls,l,mid); build(rs,mid+1,r); up(o); } IL int query(int o,int l,int r,int x,int y) { if(l<=x and y>=r)return ssum[o]; int mid=(l+r)>>1; int ret=-2147483647; if(x<=mid)ret=max(query(ls,l,mid,x,y),ret); if(y>mid)ret=max(query(rs,mid+1,r,x,y),ret); return ret; } main(void ) { in(n); build(1,1,n); printf("%lld",query(1,1,n,1,n)); }
p1115 最大子段和(線段樹)