LA 3938 - "Ray, Pass me the dishes!"(线段树)

动态最大连续和。

思路:完全参照刘汝佳厚书的思路。

几天前,就从书上得到一个思路,却不知怎么实现,于是乎,几天来一直广搜结题报告,结合人家现成的代码,今天写成了代码,又调了半下午的bug,终于ac了。

构造一课线段树,其中每个节点维护3个信息,最大连续和(x,y),最大前缀和(pre),最大后缀和(suf),虽然都叫做什么什么和,存的却都是位置标记,

1、建树

2、若干次查询

这道题目没有加入树节点的修改,算是数据结构中的基础题了。

思路来自于静态最大连续和的求解,(最大连续和或在[1...m],或在[m+1......n],或在[x...m......y])

代码如下:

#include <cstdio>
#include <algorithm>
using namespace std;
#define M 500005
struct Node{
    int x, y, pre, suf, subx, suby;
};
int n, m;
long long a[M], sum[M];
Node tree[2*M+10];
void creat(int x, int y, int o)
{
    if(x==y)
    {
        tree[o].x = x;
        tree[o].y = x;
        tree[o].pre = x;
        tree[o].suf = x;
        tree[o].subx = x;
        tree[o].suby = x;
        return;
    }
    int m = (x+y)/2;
    creat(x, m, 2*o);
    creat(m+1, y, 2*o+1);
    tree[o].x = x;
    tree[o].y = y;
    tree[o].pre = sum[tree[2*o].pre]-sum[x-1] >= sum[tree[2*o+1].pre]-sum[x-1] ? tree[2*o].pre : tree[2*o+1].pre;
    tree[o].suf = sum[y]-sum[tree[2*o].suf-1] >= sum[y]-sum[tree[2*o+1].suf-1] ? tree[2*o].suf : tree[2*o+1].suf;
    if(sum[tree[2*o].suby]-sum[tree[2*o].subx-1]>=sum[tree[2*o+1].suby]-sum[tree[2*o+1].subx-1])
        { tree[o].suby = tree[2*o].suby; tree[o].subx = tree[2*o].subx; }
    else
        { tree[o].suby = tree[2*o+1].suby; tree[o].subx = tree[2*o+1].subx; }
    if(sum[tree[2*o+1].pre]-sum[tree[2*o].suf-1] > sum[tree[o].suby]-sum[tree[o].subx-1])
        { tree[o].subx = tree[2*o].suf; tree[o].suby = tree[2*o+1].pre; }
    else if(sum[tree[2*o+1].pre]-sum[tree[2*o].suf-1] == sum[tree[o].suby]-sum[tree[o].subx-1])
    {
        if(tree[o].subx > tree[2*o].suf||(tree[o].subx == tree[2*o].suf && tree[o].suby > tree[2*o+1].pre))
            { tree[o].subx = tree[2*o].suf; tree[o].suby = tree[2*o+1].pre; }
    }
}
void buildtree()
{
    creat(1,n,1);
}
void query(int o, int ql, int qr, int &ansx, int &ansy, int &pre, int &suf)
{
    int x = tree[o].x,  y = tree[o].y;
    if(ql<=x&&qr>=y)
    {
        ansx = tree[o].subx;
        ansy = tree[o].suby;
        pre = tree[o].pre;
        suf = tree[o].suf;
        return ;
    }
    int mid = (x+y)/2;
    if(qr<=mid) query(2*o,ql,qr,ansx,ansy,pre,suf);
    else if(ql>mid) query(2*o+1,ql,qr,ansx,ansy,pre,suf);
    else
    {
        int x1, x2, y1, y2,p1,p2,s1,s2;
        query(2*o,ql,mid,x1,y1,p1,s1);
        query(2*o+1,mid+1,qr,x2,y2,p2,s2);

        pre = sum[p1]-sum[ql-1] >= sum[p2]-sum[ql-1] ? p1 : p2 ;
        suf = sum[qr]-sum[s1-1] >= sum[qr]-sum[s2-1] ? s1 : s2 ;
        if(sum[y1]-sum[x1-1] >= sum[y2]-sum[x2-1])
        {
            ansx = x1;
            ansy = y1;
        }
        else
        {
            ansx = x2;
            ansy = y2;
        }
        long long L = sum[m]-sum[s1-1];
        long long R = sum[p2]-sum[m];
        if(L+R > sum[ansy]-sum[ansx-1] || (L+R == sum[ansy]-sum[ansx-1] && ansx > s1) || (L+R == sum[ansy]-sum[ansx-1] && ansx == s1 && ansy > p2))
        {
            ansx = s1;
            ansy = p2;
        }
    }

}
int main ()
{
    int k = 0;
    while(~scanf("%d %d",&n, &m))
    {
        for(int i = 1; i <= n; ++i)
        {
            scanf("%lld",&a[i]);
            sum[i] = sum[i-1]+a[i];
        }
        buildtree();
        int ql, qr, ansx, ansy,pre,suf;
        printf("Case %d:\n",++k);//不要把case放错位置哦
        while(m--)
        {
            scanf("%d %d",&ql, &qr);
            query(1, ql, qr, ansx, ansy,pre,suf);
            printf("%d %d\n", ansx, ansy);
        }
    }
    return 0;
}


你可能感兴趣的:(LA 3938 - "Ray, Pass me the dishes!"(线段树))