解题报告:luogu P1115(模板 最大子段和)
题目链接:P1115 最大子段和
告诉你,这个我调了一天的题是橙题......
线性容易得到,放篇题解:
#include<bits/stdc++.h>
using namespace std;
int main()
{
int n[200001],p,ans[200001]={0};
int sum=-9999999;//|x|<=10000 QWQ
cin>>p;
for(int i=1;i<=p;i++)
{
cin>>n[i];//输入
ans[i]=max(ans[i-1]+n[i],n[i]);//DP
sum=max(sum,ans[i]);//取最大值也同时进行,节约时间
}
cout<<sum;//直接输出
return 0;
}
可我想到一道紫题,这样做沦为\(O(n^2)\),那我们如何维护任意区间的最大子段和,可以用线段树维护,开始想了个\(O(n^2logn)\),显然是假的,然后学了下,又出了些\(SB\)错误,终于\(AC\)了。
\(Code\):
#include<iostream>
#include<cstdio>
#include<cmath>
using namespace std;
const int MAXN=200005;
int t[MAXN],n;
struct seg_t
{
int l,r,sum,pre,suf,maxn;
seg_t()
{
l=r=sum=pre=suf=maxn=0;
}
}a[MAXN<<2];
void update(int k)
{
a[k].pre=max(a[k<<1].pre,a[k<<1].sum+a[k<<1|1].pre);
a[k].suf=max(a[k<<1|1].suf,a[k<<1|1].sum+a[k<<1].suf);
a[k].maxn=max(max(a[k<<1].maxn,a[k<<1|1].maxn),a[k<<1].suf+a[k<<1|1].pre);
a[k].sum=a[k<<1].sum+a[k<<1|1].sum;
}
void build(int k,int l,int r)
{
a[k].l=l,a[k].r=r;
if(l==r)
{
a[k].maxn=a[k].sum=a[k].suf=a[k].pre=t[l];
return;
}
int mid=(l+r)>>1;
build(k<<1,l,mid),build(k<<1|1,mid+1,r);
update(k);
}
seg_t query(int k,int l,int r)
{
int mid=(a[k].l+a[k].r)>>1;
if(a[k].l==l&&a[k].r==r) return a[k];
if(r<=mid) return query(k<<1,l,r);
else if(l>=mid+1) return query(k<<1|1,l,r);
else
{
seg_t ll,rr,ans;
ll=query(k<<1,l,mid),rr=query(k<<1|1,mid+1,r);
ans.sum=ll.sum+rr.sum;
ans.maxn=max(ll.maxn,rr.maxn);
ans.pre=max(ll.pre,ll.sum+rr.pre);
ans.suf=max(rr.suf,rr.sum+ll.suf);
ans.maxn=max(ans.maxn,ll.suf+rr.pre);
return ans;
}
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++) scanf("%d",&t[i]);
build(1,1,n);
printf("%d\n",query(1,1,n).maxn);
return 0;
}
这种线段树咱真没见过