UVA1400&LA3938 线段树

构造线段树每个节点维护三个值
max_pre 满足当前线段最大前缀和的右端点编号
max_suf 满足当前线段最大后缀和的左端点编号
max_sub 用pair维护满足当前线段最大连续和的两个端点编号
维护max_sub
有三种情况
左右端点都在 左子节点 max_sub等于左子节点的max_sub
左右端点都在 右子节点 max_sub等于右子节点的max_sub
左端点在 左子节点 右端点在 右子节点 左子节点后缀和+右子节点前缀和

#include <iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<string>

using namespace std;
typedef long long LL;
const int maxn=500000+10;
typedef pair<int,int> interval;
LL s[maxn];
int ql,qr;
LL sum(int l,int r)
{
    return s[r]-s[l-1];
}
LL sum(interval a)
{
    return s[a.second]-s[a.first-1];
}
interval better(interval a,interval b)
{
    LL tempa=sum(a),tempb=sum(b);
    if(tempa!=tempb) return tempa>tempb?a:b;
    return a<b?a:b;
}
struct tree
{
    interval max_sub[maxn<<2];
    int max_pre[maxn<<2];
    int max_suf[maxn<<2];
    void build(int node,int l,int r)
    {
        if(l==r)
        {
            max_pre[node]=max_suf[node]=l;
            max_sub[node]=make_pair(l,l);
            return ;
        }
        int mid=l+(r-l)/2,lc=(node<<1),rc=(node<<1|1);
        build(lc,l,mid);
        build(rc,mid+1,r);

        LL v1=sum(l,max_pre[lc]);
        LL v2=sum(l,max_pre[rc]);
        if(v1==v2) max_pre[node]=min(max_pre[lc],max_pre[rc]);
        else max_pre[node]=v1>v2?max_pre[lc]:max_pre[rc];

        v1=sum(max_suf[lc],r);
        v2=sum(max_suf[rc],r);

        if(v1==v2) max_suf[node]=min(max_suf[lc],max_suf[rc]);
        else max_suf[node]=v1>v2?max_suf[lc]:max_suf[rc];

        max_sub[node]=better(max_sub[lc],max_sub[rc]);
        max_sub[node]=better(max_sub[node],make_pair(max_suf[lc],max_pre[rc]));
    }
    interval pre_query(int node,int l,int r)
    {
        if(max_pre[node]<=qr) return make_pair(l,max_pre[node]);
        int m=l+(r-l)/2;
        int lc=(node<<1),rc=(node<<1|1);
        if(qr<=m)
        {
            return pre_query(lc,l,m);
        }
        interval i = pre_query(rc,m+1,r);
        i.first=l;
        return better(i,make_pair(l,max_pre[lc]));
    }
    interval suf_query(int node,int l,int r)
    {
        if(max_suf[node]>=ql) return make_pair(max_suf[node],r);
        int m=l+(r-l)/2;
        int lc=(node<<1),rc=(node<<1|1);
        if(ql>m)
        {
            return suf_query(rc,m+1,r);
        }
        interval i=suf_query(lc,l,m);
        i.second=r;
        return better(i,make_pair(max_suf[rc],r));
    }
    interval query(int node,int l,int r)
    {
        if(ql<=l&&qr>=r) return max_sub[node];
        int m=l+(r-l)/2;
        if(ql>m)
        {
            return query(node<<1|1,m+1,r);
        }
        if(qr<=m) return query(node<<1,l,m);
        int lc=(node<<1),rc=(node<<1|1);
        interval i1=suf_query(lc,l,m);
        interval i2=pre_query(rc,m+1,r);
        interval i3=better(query(lc,l,m),query(rc,m+1,r));
        return better(i3,make_pair(i1.first,i2.second));
    }
};
tree T;
int main()
{
    int n,m,a,kase=0;
    interval ans;
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        printf("Case %d:\n", ++kase);
        s[0]=0;
        for(int i = 0; i < n; ++i)
        {
            scanf("%d",&a);
            s[i+1]=s[i]+a;
        }
        T.build(1,1,n);
        while(m--)
        {
            scanf("%d%d",&ql,&qr);
            ans=T.query(1,1,n);
            printf("%d %d\n",ans.first,ans.second);
        }
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值