P1714 切蛋糕(线段树)
\(\operatorname{Solution}\)
这里提供一个线段树的写法。
虽然这道题比 SP1043 GSS1 - Can you answer these queries I 多了 \(m\) 个限制条件,但换句话说,其实就是询问 \([1,m]\) ,\([2,m+1]\) ,\(...\) ,\([n-m+1,n]\) 这 \(n-m+1\) 个长度为 \(m\) 的区间中最大子段和的最大值。于是可以枚举这 \(n-m+1\) 个区间,每次查询区间最大值。考虑到长度为 \(m\) 的区间的最大子段和的长度不可能超过 \(m\) ,于是限制条件相当于没有。
枚举 \(\operatorname{O(n)}\) ,查询 \(\operatorname{O(logn)}\) ,总复杂度 \(\operatorname{O(nlogn)}\) ,可以很轻松的通过这道题。
\(\operatorname{Code}\)
#include <bits/stdc++.h>
#define maxn 550000
#define max_INF 600
#define ll long long
using namespace std;
ll n,m;
ll a[maxn];
ll ans;
struct Tree{
ll sum,lmax,rmax,dat;
}tree[maxn<<2];
inline ll read(){
ll x=0,f=0;char c=getchar();
while(!isdigit(c)) f|=c=='-',c=getchar();
while(isdigit(c)) x=(x<<1)+(x<<3)+(c^48),c=getchar();
return f?-x:x;
}
inline void pushup(ll f){
tree[f].sum=tree[f<<1].sum+tree[f<<1|1].sum;
tree[f].lmax=max(tree[f<<1].lmax,tree[f<<1].sum+tree[f<<1|1].lmax);
tree[f].rmax=max(tree[f<<1|1].rmax,tree[f<<1].rmax+tree[f<<1|1].sum);
tree[f].dat=max(max(tree[f<<1].dat,tree[f<<1|1].dat),tree[f<<1].rmax+tree[f<<1|1].lmax);
}
inline void build(ll l,ll r,ll f){
if(l==r){
tree[f].dat=tree[f].lmax=tree[f].rmax=tree[f].sum=a[l];
return;
}
ll mid=(l+r)>>1;
build(l,mid,f<<1);
build(mid+1,r,f<<1|1);
pushup(f);
}
inline Tree query(ll l,ll r,ll f,ll cl,ll cr){
if(l>=cl&&r<=cr) return tree[f];
ll mid=(l+r)>>1;
if(cl>mid) return query(mid+1,r,f<<1|1,cl,cr);
if(cr<=mid) return query(l,mid,f<<1,cl,cr);
else{
Tree ans1,ans2,ans3;
ans1=query(l,mid,f<<1,cl,cr);
ans2=query(mid+1,r,f<<1|1,cl,cr);
ans3.sum=ans1.sum+ans2.sum;
ans3.dat=max(max(ans1.dat,ans1.rmax+ans2.lmax),ans2.dat);
ans3.lmax=max(ans1.lmax,ans1.sum+ans2.lmax);
ans3.rmax=max(ans2.rmax,ans1.rmax+ans2.sum);
return ans3;
}
}
int main(){
n=read();m=read();
for(register int i=1;i<=n;++i) a[i]=read();
build(1,n,1);
ans=0;
for(register int i=1;i<=n-m+1;++i)
ans=max(ans,query(1,n,1,i,i+m-1).dat);
printf("%lld\n",ans);
return 0;
}