UVA1400 "Ray, Pass me the dishes!" 线段树

         本来是在做伸展树的,发现了一道需要求区间最大连续和的题,然后想起了原来做的这题好像还没过...当时又是后缀,又是前缀,又是最大子区间和,直接调成傻逼了= =...这次回头做了做,感觉思路还是挺清晰的,就是第一次写搓了把区间和也记录了,实际上只记录个下标就够了,区间和预处理一下就行了。主要思路就是用线段树构造并查询四个值,最大子区间的左右端点l_id,r_id,区间最大后缀的起点s_id,区间最大前缀的终点p_id,构造完了直接在线查询就行了...

         

#include <cstdio>
#include <algorithm>
#include <iostream>
#include <cmath>
#include <string>
#include <cstring>
#include <queue>
#include <stack>
#include <map>
#define lson id<<1,l,m
#define rson id<<1|1,m+1,r
using namespace std;
const int maxn=500000+500;
typedef long long ll;
ll sum[maxn];
int l_id[maxn<<2],r_id[maxn<<2],p_id[maxn<<2],s_id[maxn<<2];
int n,m,p,q;
int tt;
struct node
{
    int l,r,s,p;
    node(){}
    node(int x1,int x2,int x3,int x4)
    {
        l=x1;
        r=x2;
        s=x3;
        p=x4;
    }
};
struct segmenttree
{
    void pushup(int id,int l,int r)
    {
        int m=(l+r)>>1;

        if (sum[r_id[id<<1]]-sum[l_id[id<<1]-1]<sum[r_id[id<<1|1]]-sum[l_id[id<<1|1]-1])
        {
            l_id[id]=l_id[id<<1|1];
            r_id[id]=r_id[id<<1|1];
        }
        else
        {
            l_id[id]=l_id[id<<1];
            r_id[id]=r_id[id<<1];
        }
        if (sum[r_id[id]]-sum[l_id[id]-1]<sum[p_id[id<<1|1]]-sum[s_id[id<<1]-1] ||
            (sum[r_id[id]]-sum[l_id[id]-1]==sum[p_id[id<<1|1]]-sum[s_id[id<<1]-1] && l_id[id]>s_id[id<<1])||
            (sum[r_id[id]]-sum[l_id[id]-1]==sum[p_id[id<<1|1]]-sum[s_id[id<<1]-1] && l_id[id]==s_id[id<<1] && r_id[id]>p_id[id<<1|1]))
            {
                l_id[id]=s_id[id<<1];
                r_id[id]=p_id[id<<1|1];
            }

        if (sum[r]-sum[s_id[id<<1|1]-1]>sum[r]-sum[s_id[id<<1]-1])
        {
            s_id[id]=s_id[id<<1|1];
        }
        else s_id[id]=s_id[id<<1];

        if (sum[p_id[id<<1|1]]-sum[l-1]>sum[p_id[id<<1]]-sum[l-1])
        {
            p_id[id]=p_id[id<<1|1];
        }
        else p_id[id]=p_id[id<<1];

    }
    void build(int id,int l,int r)
    {
        if (l==r)
        {
            l_id[id]=r_id[id]=s_id[id]=p_id[id]=l;
            return ;
        }
        int m=(l+r)>>1;
        build(lson);
        build(rson);
        pushup(id,l,r);
    }
    node query(int L,int R,int id,int l,int r)
    {
        if (L==l && r== R)
        {
            return node(l_id[id],r_id[id],s_id[id],p_id[id]);
        }
        int m=(l+r>>1);
        if (R<=m)
        {
            return query(L,R,lson);
        }
        else
        if (L>m)
        {
            return query(L,R,rson);
        }
        else
        {
            node p1=query(L,m,lson);
            node p2=query(m+1,R,rson);
            node res;
            if (sum[p1.r]-sum[p1.l-1]<sum[p2.r]-sum[p2.l-1])
            {
                res.l=p2.l;
                res.r=p2.r;
            }
            else
            {
                res.l=p1.l;
                res.r=p1.r;
            }

            if (sum[p2.p]-sum[p1.s-1]>sum[res.r]-sum[res.l-1] ||
                (sum[p2.p]-sum[p1.s-1]==sum[res.r]-sum[res.l-1] && res.l>p1.s) ||
                (sum[p2.p]-sum[p1.s-1]==sum[res.r]-sum[res.l-1] && res.l==p1.s && res.r>p2.p))
            {
                res.l=p1.s;
                res.r=p2.p;
            }
            if (sum[r]-sum[p2.s-1]>sum[r]-sum[p1.s-1])
            res.s=p2.s;
            else res.s=p1.s;

            if (sum[p2.p]-sum[l-1]>sum[p1.p]-sum[l-1])
            res.p=p2.p;
            else res.p=p1.p;
            return res;
        }
    }
    void init()
    {
        memset(l_id,0,sizeof l_id);
        memset(r_id,0,sizeof r_id);
        memset(s_id,0,sizeof s_id);
        memset(p_id,0,sizeof p_id);
    }
}sgt;
int main()
{
//    freopen("in.txt","r",stdin);
    int tt=0;
    while(~scanf("%d%d",&n,&m))
    {
        tt++;
        sgt.init();
        for (int i=1; i<=n; i++)
        {
            scanf("%lld",&sum[i]);
        }

        for (int i=2; i<=n; i++)
        sum[i]+=sum[i-1];
        sgt.build(1,1,n);
        node ans;
        int x,y;
        printf("Case %d:\n",tt);
        for (int i=1; i<=m; i++)
        {
            scanf("%d%d",&x,&y);
            ans=sgt.query(x,y,1,1,n);

            printf("%d %d\n",ans.l,ans.r);
        }
    }
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值