UVAlive - 3938 —— "Ray, Pass me the dishes!" 【线段树】

http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=22105

#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#define INF 0x3f3f3f3f
#define lson rt<<1, l, m
#define rson rt<<1|1, m+1, r
using namespace std;

typedef long long LL;

const int MAXN = 524288 + 5;
int n;
struct P {
    LL d, sum, head, tail;
    int l, r, head_bound, tail_bound;
} p[MAXN << 1];

void pushup(int rt)
{
    int L = rt<<1, R = rt<<1|1;
    if(p[L].d >= p[R].d) {
        p[rt].d = p[L].d;
        p[rt].l = p[L].l;
        p[rt].r = p[L].r;
    } else {
        p[rt].d = p[R].d;
        p[rt].l = p[R].l;
        p[rt].r = p[R].r;
    }
    if(p[rt].d < p[L].tail + p[R].head) {
        p[rt].d = p[L].tail + p[R].head;
        p[rt].l = p[L].tail_bound;
        p[rt].r = p[R].head_bound;
    } else if(p[rt].d == p[L].tail + p[R].head) {
        if(p[rt].l > p[L].tail_bound) {
            p[rt].l = p[L].tail_bound;
            p[rt].r = p[R].head_bound;
        } else if(p[rt].l == p[L].tail_bound) {
            if(p[rt].r > p[R].head_bound) {
                p[rt].r = p[R].head_bound;
            }
        }
    }

    if(p[L].head >= p[L].sum + p[R].head) {
        p[rt].head = p[L].head;
        p[rt].head_bound = p[L].head_bound;
    } else {
        p[rt].head = p[L].sum + p[R].head;
        p[rt].head_bound = p[R].head_bound;
    }

    if(p[R].tail > p[R].sum + p[L].tail) { // 仔细斟酌一下,为了取最小下标,这里要取大于号
        p[rt].tail = p[R].tail;
        p[rt].tail_bound = p[R].tail_bound;
    } else {
        p[rt].tail = p[R].sum + p[L].tail;
        p[rt].tail_bound = p[L].tail_bound;
    }

    p[rt].sum = p[L].sum + p[R].sum;
}

void build(int rt, int l, int r)
{
    if(l == r) {
        scanf("%lld", &p[rt].d);
        p[rt].sum = p[rt].head = p[rt].tail = p[rt].d;
        p[rt].l = p[rt].r = p[rt].head_bound = p[rt].tail_bound = l;
        return;
    }

    int m = (l + r) >> 1;
    build(lson);
    build(rson);
    pushup(rt);
}

P query(int ql, int qr, int rt, int l, int r)
{
    if(ql <= l && r <= qr)    return p[rt];

    int m = (l + r) >> 1;
    P left, right, ret;
    bool ok1 = 0, ok2 = 0;
    if(ql <= m) {
        left = query(ql, qr, lson);
        ok1 = 1;
    }
    if(qr > m) {
        right = query(ql, qr, rson);
        ok2 = 1;
    }

    if(ok1) {
        ret = left;
        if(ok2) {
            if(ret.d < right.d) {
                ret.d = right.d;
                ret.l = right.l;
                ret.r = right.r;
            }
            if(ret.d < left.tail + right.head) {
                ret.d = left.tail + right.head;
                ret.l = left.tail_bound;
                ret.r = right.head_bound;
            } else if(ret.d == left.tail + right.head){
                if(ret.l > left.tail_bound) {
                    ret.l = left.tail_bound;
                    ret.r = right.head_bound;
                } else if(ret.l == left.tail_bound) {
                    if(ret.r > right.head_bound) {
                        ret.r = right.head_bound;
                    }
                }
            }

            if(left.head >= left.sum + right.head) {
                ret.head = left.head;
                ret.head_bound = left.head_bound;
            } else {
                ret.head = left.sum + right.head;
                ret.head_bound = right.head_bound;
            }

            if(right.tail > right.sum + left.tail) {
                ret.tail = right.tail;
                ret.tail_bound = right.tail_bound;
            } else {
                ret.tail = right.sum + left.tail;
                ret.tail_bound = left.tail_bound;
            }

            ret.sum = left.sum + right.sum;
        }
    } else if(ok2) {
        ret = right;
    }
    return ret;
}

int main ()
{
    int m, a, b, kase=1;
    while(scanf("%d%d", &n, &m) != EOF) {
        build(1, 1, n);
        printf("Case %d:\n", kase++); // 注意Case的位置在这里,我把它写到了下面的while里面去了,WA到哭泣。。。
        while(m--) {
            scanf("%d%d", &a, &b);
            P ans = query(a, b, 1, 1, n);
            printf("%d %d\n", ans.l, ans.r);
        }
    }
    return 0;
}

UVAlive - 3938 —— "Ray, Pass me the dishes!" 【线段树】

时间: 2024-10-22 22:37:08

UVAlive - 3938 —— "Ray, Pass me the dishes!" 【线段树】的相关文章

uvalive 3938 &quot;Ray, Pass me the dishes!&quot; 线段树 区间合并

题意:求q次询问的静态区间连续最大和起始位置和终止位置 输出字典序最小的解. 思路:刘汝佳白书 每个节点维护三个值 pre, sub, suf 最大的前缀和, 连续和, 后缀和 然后这个题还要记录解的位置所以还要区间总和sum 1 #include<iostream> 2 #include<string> 3 #include<algorithm> 4 #include<cstdlib> 5 #include<cstdio> 6 #include

UVALive3938 &quot;Ray, Pass me the dishes!&quot; 线段树动态区间最大和

AC得相当辛苦的一道题,似乎不难,但是需要想仔细, 开始的时候的错误思路----是受之前做过的区间最长连续子串影响http://blog.csdn.net/u011026968/article/details/38357157 区间合并的时候,我直接按照---如果(左子树的最大前缀和长度==左子树的长度 && 右子树的前缀和>0),就合并左前缀,这想法有两个错误:1.右子树的前缀和==0的时候是不是要合并区间呢?题目要求x尽量小,如果x相同y尽量小(x是ans的区间左端点,y是Ans

UVA 1400 1400 - &quot;Ray, Pass me the dishes!&quot;(线段树)

UVA 1400 - "Ray, Pass me the dishes!" 题目链接 题意:给定一个序列,每次询问一个[L,R]区间,求出这个区间的最大连续子序列和 思路:线段树,每个节点维护3个值,最大连续子序列,最大连续前缀序列,最大连续后缀序列,那么每次pushup的时候,根据这3个序列去拼凑得到新的一个结点即可 代码: #include <cstdio> #include <cstring> #include <algorithm> usin

uva 1400 - &quot;Ray, Pass me the dishes!&quot;(线段树)

题目链接:uva 1400 - "Ray, Pass me the dishes!" 题目大意:给定一个长度为n个整数序列,对m次询问作出回答,对于每次询问(a,b),找到两个下标x,y使得x到y的连续和为区间a,b中最大的连续和,如果存在多解优先x小,然后y小. 解题思路:线段树,对于每个节点维护三个线段值: max_sub:区间连续最大和 max_prefix:区间连续前缀最大和 max_suffix:区间连续后缀最大和 建树的过程维护三个值,查询时只需考虑左右子节点的max_su

Uva 1400 &quot;Ray, Pass me the dishes!&quot; ( 线段树 + 区间查询 )

Uva  1400 "Ray, Pass me the dishes!" (线段树 + 区间查询) 题意: 给顶一个长度为n的整数序列D,我们的任务是对m的询问做出回答对于询问(a,b),需要找到两个下标x和y,是的 a <= x <= y <=b并且Dx+...........Dy 尽量大. x,y尽量小 分析: 这题是做线段树比较好的一题,大白书上介绍的是维护了三个域,maxsub,maxpre,maxsuf这里也可以只维护两个域,再最后再考虑跨区间的问题这里没有

UVALive 3938 Ray, Pass me the dishes! (动态最大连续和)

题意:求一个动态区间的最大连续和. 静态版本的O(n)算法显示不适用了,但是可以用线段树分治,因为一个连续和要在两边的区间,要么跨越两边,对于一个结点维护最大前缀和,后缀和,子区间连续和. 题目要求输出区间,所以还要保存连续和最大的区间,以及前缀和,后缀和的位置.为了维护最大前缀和以及后缀和还需要一个区间和. 写的时候稍微麻烦一点,更新写成一个函数会方便很多.还好一遍过了... #include<bits/stdc++.h> using namespace std; const int max

LA3938:&quot;Ray, Pass me the dishes!&quot;(线段树)

Description After doing Ray a great favor to collect sticks for Ray, Poor Neal becomes very hungry. In return for Neal's help, Ray makes a great dinner for Neal. When it is time for dinner, Ray arranges all the dishes he makes in a single line (actua

UVA - 1400&quot;Ray, Pass me the dishes!&quot;(线段树)

题目链接 题目大意:给你N个数字,要求你动态的给出L到R之间,X>= L && Y<=R,使得X,Y这段的连续和是LR之间的最大连续和,如果有多解,输出X小的,接着是Y小的. 解题思路:结点保存三个附加线段,max_sub, max_suffix, max_prefix.对于每次查询最大的连续和要不出现在左子树的max_sub, 要不就是右子树的max_sub, 要不就是左子树的max_suffix + 右子树的max_prefix.然后每次查询的时候都返回一个新的节点,是新的

LA3938 &quot;Ray, Pass me the dishes!&quot; (线段树区间合并)

题目:http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=22105 题意:给定整数n和m,给出一个n个元素的序列,查询m次给定区间[L,R]的最大连续和的位置[x,y],有多个区间输出x最小的,还有多个的话输出y最小的. 分析:每个节点存8个信息,最大连续和.最大后缀和.最大前缀和.区间和.前缀末位置.后缀首位置.最大连续和的首位置和末位置. 最大连续和=max(lson最大连续和,rson最大连续和,lson最大后缀+rso