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;
}
posted @ 2021-10-21 21:11  XeniaF  阅读(40)  评论(0编辑  收藏  举报