UVALive - 3938 Ray, Pass me the dishes!

题目地址:

https://icpcarchive.ecs.baylor.edu/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=1939

 

这题是蓝书上的题,题目大意与思路如下:

 

我主要说一下实现细节:

(1)维护整个序列的前缀和数组。书里没有讲到的是,维护max_prefix和max_suffix需要区间的和。因为题目要求返回的是两个区间的端点,所以我们的递归函数应该返回区间端点(因为我们不能通过和来拿到区间端点),然后通过前缀和数组,我们可以方便地访问每个区间的和。

(2)线段树里保存区间端点,而不是和

(3)防止溢出,每个数虽然在int里,但它们的和会溢出。

下面给出代码:

data[i][0]保存max_sub左端点,data[i][1]保存max_sub右端点,data[i][2]保存max_suffix右端点,data[i][3]保存max_preffix左端点。

然后使用数组保存线段树2*node+1为左节点,2*node+2为右节点。

#include <bits/stdc++.h>

using namespace std;

int dia[500005];
long long sums[500005];
int data[2000005][4];
int n;


void buildTree(int node, int l, int r)
{
    //cout<<l<<" "<<r<<" "<<node<<endl;
    long long tmp, tmp1, tmp2, tmp3;
    int m = l +(r-l)/2;
    if((l==n-1)||(r-l==1))
    {
        data[node][0] = l;
        data[node][1] = l+1;
        data[node][2] = l+1;
        data[node][3] = l;
        return;
    }
    buildTree(2*node+1,l,m);
    if(m<n)
        buildTree(2*node+2,m,r);
    else
    {
        data[node][0] = data[2*node+1][0];
        data[node][1] = data[2*node+1][1];
        data[node][2] = data[2*node+1][2];
        data[node][3] = data[2*node+1][3];
        return;
    }
    tmp1 = sums[data[2*node+1][1]-1] - sums[data[2*node+1][0]-1];
    tmp2 = sums[data[2*node+2][1]-1] - sums[data[2*node+2][0]-1];
    tmp3 = sums[data[2*node+2][2]-1]-sums[data[2*node+1][3]-1];
    tmp = max(max(tmp1,tmp2),tmp3);
    //cout<<node<<" "<<tmp1<<tmp2<<tmp3<<endl;
    if(tmp==tmp1)
    {
        if(tmp1==tmp3&&data[2*node+1][0]>data[2*node+1][3])
        {
            data[node][0] = data[2*node+1][3];
            data[node][1] = data[2*node+2][2];
        }
        else
        {
            data[node][0]=data[2*node+1][0];
            data[node][1]=data[2*node+1][1];
        }
    }
    else if(tmp == tmp3)
    {
        data[node][0] = data[2*node+1][3];
        data[node][1] = data[2*node+2][2];
    }
    else
    {
        data[node][0]=data[2*node+2][0];
        data[node][1]=data[2*node+2][1];
    }

    if(sums[data[2*node+2][2]-1]-sums[data[2*node+1][2]-1]>0)
        data[node][2] = data[2*node+2][2];
    else
        data[node][2] = data[2*node+1][2];
    if(sums[data[2*node+2][3]-1]-sums[data[2*node+1][3]-1]>=0)
        data[node][3] = data[2*node+1][3];
    else
        data[node][3] = data[2*node+2][3];
    /*int i,j;
    for(i=0;i<5;i++)
    {
        for(j=0;j<4;j++)
        {
            printf("%d ",data[i][j]);
        }
        printf("\n");
    }*/
}

void query(int a, int b, int l, int r, int node, int c[])
{
    int i,j;
    //cout<<l<<" "<<r<<" "<<a<<" "<<b<<endl;
    if(b-a==1)
    {
        c[0]=a;
        c[1]=a+1;
        c[2]=a+1;
        c[3]=a;
        return;
    }
    if(a==l&&b==r)
    {
        c[0] = data[node][0];
        c[1] = data[node][1];
        c[2] = data[node][2];
        c[3] = data[node][3];
        return;
    }
    int m = l +(r-l)/2;
    if(m<=a)
    {
        query(a,b, m, r, 2*node+2, c);
        return;
    }
    if(m>=b)
    {
        query(a,b,l,m,2*node+1, c);
        return;
    }
    int c1[4], c2[4];
    long long tmp, tmp1, tmp2, tmp3;
    query(a,m,l,m,2*node+1,c1);
    query(m,b,m,r,2*node+2,c2);
    tmp1 = sums[c1[1]-1] - sums[c1[0]-1];
    tmp2 = sums[c2[1]-1] - sums[c2[0]-1];
    tmp3 = sums[c2[2]-1]-sums[c1[3]-1];
    tmp = max(max(tmp1,tmp2),tmp3);
    //cout<<node<<" "<<tmp1<<tmp2<<tmp3<<endl;
    if(tmp==tmp1)
    {
        if(tmp1==tmp3&&c1[0]>c1[3])
        {
            c[0] = c1[3];
            c[1] = c2[2];
        }
        else
        {
            c[0]=c1[0];
            c[1]=c1[1];
        }
    }
    else if(tmp == tmp3)
    {
        c[0] = c1[3];
        c[1] = c2[2];
    }
    else
    {
        c[0]=c2[0];
        c[1]=c2[1];
    }

    if(sums[c2[2]-1]-sums[c1[2]-1]>0)
        c[2] = c2[2];
    else
        c[2] = c1[2];
    if(sums[c2[3]-1]-sums[c1[3]-1]>=0)
        c[3] = c1[3];
    else
        c[3] = c2[3];
    return;

}

int main()
{
    int m, i, j, t=0;
    int c[4];
    while(scanf("%d%d",&n,&m)==2)
    {
        t++;
        for(i=0;i<n;i++)
        {
            scanf("%d",&dia[i]);
            if(i==0)
                sums[0]=dia[0];
            else
                sums[i]=sums[i-1]+dia[i];
        }
        int a = log(n)/log(2), b, d = a;
        //cout<<a<<endl;
        buildTree(0, 0, int(pow(2,a+1)));
        /*for(i=0;i<8;i++)
        {
            for(j=0;j<4;j++)
            {
                printf("%d ",data[i][j]);
            }
            printf("\n");
        }*/
        printf("Case %d:\n",t);
        for(i=0;i<m;i++)
        {
            scanf("%d%d",&a,&b);
            query(a-1,b,0, int(pow(2,d+1)),0,c);
            printf("%d %d\n",c[0]+1, c[1]);
        }
    }
}

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值