区间最大子段和 cid=1761#problem/E

题意: 求子段的左右端点被分别限制在对应区间中的最大子段和


两个限制区间的相对位置分五种情况讨论,用线段树查询区间子段和

#include<bits/stdc++.h>
#define ls (node<<1)
#define rs (node<<1|1)
using namespace std;
typedef long long ll;
const int N=100005;
int n,m;
ll a[N];
ll f[N][20];
ll g[N][20];
ll sum[N];
struct Segtree
{
    ll max,vl,vr,sum;
}Tree[N<<3];
void updata(int node)
{
    Tree[node].max=max(Tree[ls].max,max(Tree[rs].max,Tree[ls].vr+Tree[rs].vl));
    Tree[node].sum=Tree[ls].sum+Tree[rs].sum;
    Tree[node].vl=max(Tree[ls].vl,Tree[ls].sum+Tree[rs].vl);
    Tree[node].vr=max(Tree[rs].vr,Tree[rs].sum+Tree[ls].vr);
}
void build(int l,int r,int node)
{
    if(l==r)
    {
        Tree[node].sum=a[l];
        Tree[node].max=a[l];
        Tree[node].vl=a[l];
        Tree[node].vr=a[l];
        return ;
    }
    int mid=(l+r)>>1;
    build(l,mid,ls);
    build(mid+1,r,rs);
    updata(node);
}

Segtree query(int l,int r,int node,int sa,int se)
{
    if(sa<=l && r<=se)return Tree[node];
    int mid=(l+r)>>1;
    if(sa>mid)return query(mid+1,r,rs,sa,se);
    if(se<=mid)return query(l,mid,ls,sa,se);
    Segtree t,lson,rson;
    lson=query(l,mid,ls,sa,se);
    rson=query(mid+1,r,rs,sa,se);
    t.vl=max(lson.vl,lson.sum+rson.vl);t.vr=max(rson.vr,lson.vr+rson.sum);
    t.sum=lson.sum+rson.sum;
    t.max=max(lson.vr+rson.vl,max(lson.max,rson.max));
    return t;
}

void ST_prework()
{
    for (int i = 1; i <= n; i++)
    {
        f[i][0] = sum[i];
        g[i][0] = sum[i];
    }
    for (int i = 1, imax = log2(n); i <= imax; i++)
    {
        for (int j = 1; j + (1 << i) - 1 <= n; j++)
        {
            f[j][i] = max(f[j][i - 1], f[j + (1 << i - 1)][i - 1]);
            g[j][i] = min(g[j][i - 1], g[j + (1 << i - 1)][i - 1]);
        }
    }
}

int ST_max(int l, int r) 
{
    int k = log2(r - l + 1);                     
    return max(f[l][k], f[r - (1 << k) + 1][k]); 
}
int ST_min(int l, int r) 
{
    int k = log2(r - l + 1);                     
    return min(g[l][k], g[r - (1 << k) + 1][k]); 
}
int main()
{
    int _;
    for(scanf("%d",&_);_;_--)
    {
        scanf("%d",&n);
        sum[0]=0;
        for(int i=1;i<=n;i++)
        {
            scanf("%lld",&a[i]);
            sum[i]=sum[i-1]+a[i];
        }
        ST_prework();
        build(1,n,1);
        int l1,l2,r1,r2,m;
        scanf("%d",&m);
        Segtree tmp;
        while(m--)
        {
            scanf("%d%d%d%d",&l1,&r1,&l2,&r2);
            ll ans=0;
            if(r1<=l2)
            {
                l1--;
                r1--;
                if(r1==0)
                    ans=ST_max(l2,r2);
                else if(l1==0)
                {
                    ans=ST_max(l2,r2)-min(0,ST_min(l1+1,r1));
                }
                else
                {
                    ans=ST_max(l2,r2)-ST_min(l1,r1);
                }
            }
            else if(l2<=l1&&r2>=r1)
            {
                tmp=query(1,n,1,l1,r1);
                ans=max(tmp.max,tmp.vr+query(1,n,1,r1,r2).vl-a[r1]);
            }
            else if(l1<=l2&&r1>=r2)
            {
                tmp=query(1,n,1,l2,r2);
                ans=max(tmp.max,query(1,n,1,l1,l2).vr+tmp.vl-a[l2]);
            }
            else if(l2<=l1&&l1<=r2&&r2<=r1)
            {
                ans=query(1,n,1,l1,r2).max;
            }
            else if(l1<=l2&&l2<=r1&&r1<=r2)
            {
                ans=max(query(1,n,1,l1,l2).vr+query(1,n,1,l2,r2).vl-a[l2],max(query(1,n,1,l1,r1).vr+query(1,n,1,r1,r2).vl-a[r1],query(1,n,1,l2,r1).max));
            }
            printf("%lld\n",ans);
        }
    }
    return 0;
}
posted @ 2020-06-26 21:47  Zeronera  阅读(130)  评论(0)    收藏  举报