​点击打开链接​

一 线段树

一个子段肯定是由两个前缀做差相得 那么对于每一个前缀 就看它前边比它小的最大的前缀 做差取最大值 线段树维护一下

#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define N 0x3f3f3f3f3f3f3f3f

struct node
{
int l;
int r;
ll val;
};

map <ll,int> mp;
node tree[200010];
ll sum[50010],pre[50010];
int n,m;

void pushup(int cur)
{
tree[cur].val=max(tree[2*cur].val,tree[2*cur+1].val);
return;
}

void build(int l,int r,int cur)
{
int m;
tree[cur].l=l;
tree[cur].r=r;
tree[cur].val=-N;
if(l==r) return;
m=(l+r)/2;
build(l,m,2*cur);
build(m+1,r,2*cur+1);
return;
}

ll query(int pl,int pr,int cur)
{
ll res;
if(pl<=tree[cur].l&&tree[cur].r<=pr)
{
return tree[cur].val;
}
res=-N;
if(pl<=tree[2*cur].r) res=max(res,query(pl,pr,2*cur));
if(pr>=tree[2*cur+1].l) res=max(res,query(pl,pr,2*cur+1));
return res;
}

void update(int tar,int cur)
{
if(tree[cur].l==tree[cur].r)
{
tree[cur].val=pre[tree[cur].l];
return;
}
if(tar<=tree[2*cur].r) update(tar,2*cur);
else update(tar,2*cur+1);
pushup(cur);
return;
}

int main()
{
ll val,ans;
int i,l,r;
scanf("%d",&n);
for(i=1;i<=n;i++)
{
scanf("%lld",&val);
sum[i]=sum[i-1]+val;
pre[i]=sum[i];
}
mp.clear();
sort(pre+1,pre+n+1);
for(i=1,m=0;i<=n;i++)
{
if(m==0||pre[m]!=pre[i])
{
pre[++m]=pre[i];
mp[pre[m]]=m;
}
}
build(1,m,1);
ans=N;
for(i=1;i<=n;i++)
{
if(sum[i]>0) ans=min(ans,sum[i]);
}
for(i=1;i<=n;i++)
{
l=1,r=mp[sum[i]]-1;
if(l<=r)
{
val=query(1,mp[sum[i]]-1,1);
if(val!=-N)
{
ans=min(ans,sum[i]-val);
}
}
update(mp[sum[i]],1);
}
printf("%lld\n",ans);
return 0;
}

 

二 贪心排序

上一个解法是按端点来考虑 这个解法是看别人的 按照取值来考虑 一个正子段肯定是一个在后的大前缀减去在前的小前缀 所以先按前缀的值升序排序 又因为同值的前缀作差为零没意义 所以同值前缀位置越靠后则排序是越往前放

这样所有的前缀首先按取值分成了很多段 每段取值相同 而两端交界处因为“同值前缀位置越靠后则排序是越往前放”所以会在这里产生最优解

#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define N 0x3f3f3f3f3f3f3f3f

struct node
{
ll sum;
int pos;
};

node pre[50010];
int n;

bool cmp(node n1,node n2)
{
if(n1.sum==n2.sum) return n1.pos>n2.pos;
else return n1.sum<n2.sum;
}

int main()
{
ll val,minn;
int n,i;
scanf("%d",&n);
for(i=1;i<=n;i++)
{
scanf("%lld",&val);
pre[i].sum=pre[i-1].sum+val;
pre[i].pos=i;
}
sort(pre+1,pre+n+1,cmp);
minn=N;
for(i=1;i<=n;i++)
{
if(pre[i].sum>0)
{
minn=min(minn,pre[i].sum);
}
}

for(i=1;i<=n;i++)
{
if(pre[i].pos>pre[i-1].pos&&pre[i].sum>pre[i-1].sum)
{
minn=min(minn,pre[i].sum-pre[i-1].sum);
}
}
printf("%lld\n",minn);
return 0;
}