uvalive 3938 ( 动态最大连续和 )

思路: 记录每一个节点最大前缀和  和  最大后缀和   和最大子序列的 <x,y>  主要是注意在push_up的时候 注意区间的合并。

代码: 

#include<bits/stdc++.h>
#define lson (i<<1)
#define rson (i<<1|1)

using namespace std;
typedef long long ll;
typedef pair<int ,int > pii;

const int N =500000+5;

struct node
{
    int l,r;
    pii maxsub;
    int pre;
    int post;
}tree[N<<2];

ll sum[N];

ll getsum(int l,int r)
{
    return sum[r]-sum[l-1];
}

pii better(pii a,pii b)
{
    ll sum1=getsum(a.first,a.second);  ll sum2=getsum(b.first,b.second);
    if(sum1!=sum2){
        return sum1>sum2?a:b;
    }
    return a<b?a:b; // 返回下标小的
}

void build(int i,int l,int r)
{
    tree[i].l=l; tree[i].r=r;
    if(l==r){
        tree[i].maxsub=pii(l,l);
        tree[i].post=tree[i].pre=l;
        return ;
    }

    int mid=(l+r)>>1;
    build(lson,l,mid);
    build(rson,mid+1,r);
    // 计算前缀和
    ll sum1=getsum(l,tree[lson].pre);
    ll sum2=getsum(l,tree[rson].pre);
    if(sum1==sum2){
        tree[i].pre=min(tree[lson].pre,tree[rson].pre);
    }
    else{
        tree[i].pre=sum1>sum2?tree[lson].pre:tree[rson].pre;
    }
    // 计算后缀和
    sum1=getsum(tree[lson].post,r);
    sum2=getsum(tree[rson].post,r);
    if(sum1==sum2){
        tree[i].post=min(tree[lson].post,tree[rson].post);
    }
    else tree[i].post=sum1>sum2?tree[lson].post:tree[rson].post;

    tree[i].maxsub=better(tree[lson].maxsub,tree[rson].maxsub);
    tree[i].maxsub=better(tree[i].maxsub,pii(tree[lson].post,tree[rson].pre));
    return ;
}

pii query_post(int i,int l,int r)
{
    if(tree[i].post>=l) return pii(tree[i].post,r);
    int mid=(tree[i].l+tree[i].r)>>1;
    if(l>mid) return query_post(rson,l,r);

    pii x1=query_post(lson,l,mid);
    x1.second=r;
    return better(x1,pii(tree[rson].post,r));
}

pii query_pre(int i,int l,int r)
{
    if(tree[i].pre<=r) return pii(l,tree[i].pre);
    int mid=(tree[i].l+tree[i].r)>>1;

    if(r<=mid) return query_pre(lson,l,r);

    pii x1=query_pre(rson,mid+1,r);
    x1.first=l;
    return better(x1,pii(l,tree[lson].pre));
}

pii query(int i,int l,int r)
{
    if(l==tree[i].l&&r==tree[i].r){
        return tree[i].maxsub;
    }

    int mid=(tree[i].l+tree[i].r)>>1;
    if(r<=mid) return query(lson,l,r);
    else if(l>mid) return query(rson,l,r);
    pii x1=query_post(lson,l,mid); // 左子树的后缀
    pii x2=query_pre(rson,mid+1,r);  // 右子树的前缀
    //cout<<"lala"<<x1.first<<" "<<x2.second<<endl;
    pii x3=better(query(lson,l,mid),query(rson,mid+1,r));
    return better( x3, pii(x1.first,x2.second) );
}

int n,m;

int main()
{
    int kk=0;
    while(cin>>n>>m)
    {
        ll x;
        memset(sum,0,sizeof(sum));
        for(int i=1;i<=n;i++)
        {
            scanf("%lld",&x);
            sum[i]=sum[i-1]+x;
        }

        build(1,1,n);
        /*
        for(int i=1;i<=10;i++)
        {
            cout<<tree[i].l<<" "<<tree[i].r<<" "<<tree[i].maxsub.first<<" "<<tree[i].maxsub.second<<" "<<tree[i].pre<<" "<<tree[i].post<<endl;
        }
        */
        int l,r;
        printf("Case %d:\n",++kk);
        while(m--)
        {
            scanf("%d %d",&l,&r);
            pii ans=query(1,l,r);
            printf("%d %d\n",ans.first,ans.second);
        }

    }

    return 0;
}

/*

4 3
4 5 -7 6
2 4
3 4
1 4

*/

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值