UVA 1400 1400 - "Ray, Pass me the dishes!"(线段树)

UVA 1400 - "Ray, Pass me the dishes!"

题目链接

题意:给定一个序列,每次询问一个[L,R]区间。求出这个区间的最大连续子序列和

思路:线段树,每一个节点维护3个值。最大连续子序列。最大连续前缀序列,最大连续后缀序列,那么每次pushup的时候,依据这3个序列去拼凑得到新的一个结点就可以

代码:

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;

#define lson(x) ((x<<1) + 1)
#define rson(x) ((x<<1) + 2)
#define MP(a, b) make_pair(a, b)

typedef long long ll;
typedef pair<int, int> Point;

const int N = 500005;

int n, m;
ll a[N], sum[N];

struct Node {
    int l, r;
    int prex, sufx;
    Point sub;
} node[4 * N];

ll get(Point x) {
    return sum[x.second] - sum[x.first - 1];
}

bool Max(Point a, Point b) {
    long long sa = get(a);
    long long sb = get(b);
    if (sa != sb) return sa > sb;
    return a < b;
}

Point Maxsub(Node a, Node b) {
    Point ans;
    if (Max(a.sub, b.sub)) ans = a.sub;
    else ans = b.sub;
    if (Max(MP(a.sufx, b.prex), ans)) ans = MP(a.sufx, b.prex);
    return ans;
}

int Maxpre(Node a, Node b) {
    Point ans = MP(a.l, a.prex);
    if (Max(MP(a.l, b.prex), ans)) ans = MP(a.l, b.prex);
    return ans.second;
}

int Maxsuf(Node a, Node b) {
    Point ans = MP(b.sufx, b.r);
    if (Max(MP(a.sufx, b.r), ans)) ans = MP(a.sufx, b.r);
    return ans.first;
}

Node pushup(Node a, Node b) {
    Node ans;
    ans.l = a.l; ans.r = b.r;
    ans.sub = Maxsub(a, b);
    ans.prex = Maxpre(a, b);
    ans.sufx = Maxsuf(a, b);
    return ans;
}

void build(int l, int r, int x) {
    if (l == r) {
	node[x].l = l; node[x].r = r;
	node[x].prex = node[x].sufx = l;
	node[x].sub = MP(l, l);
	return ;
    }
    int mid = (l + r) / 2;
    build(l, mid, lson(x));
    build(mid + 1, r, rson(x));
    node[x] = pushup(node[lson(x)], node[rson(x)]);
}

Node Query(int l, int r, int x) {
    if (l <= node[x].l && r >= node[x].r)
	return node[x];
    int mid = (node[x].l + node[x].r) / 2;
    Node ans;
    if (l <= mid && r > mid)
	ans = pushup(Query(l, r, lson(x)), Query(l, r, rson(x)));
    else if (l <= mid) ans = Query(l, r, lson(x));
    else if (r > mid) ans = Query(l, r, rson(x));
    return ans;
}

int main() {
    int cas = 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];
	}
	build(1, n, 0);
	printf("Case %d:\n", ++cas);
	int a, b;
	while (m--) {
	    scanf("%d%d", &a, &b);
	    Node ans = Query(a, b, 0);
	    printf("%d %d\n", ans.sub.first, ans.sub.second);
	}
    }
    return 0;
}
时间: 2024-10-13 16:22:29

UVA 1400 1400 - &quot;Ray, Pass me the dishes!&quot;(线段树)的相关文章

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

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 u

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这里也可以只维护两个域,再最后再考虑跨区间的问题这里没有

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 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

&quot;Ray, Pass me the dishes!&quot;

uvaLive3938:https://icpcarchive.ecs.baylor.edu/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=1939 题意:给你n个数,然后给你一个区间,让你查询这个区间内最大和连续子区间. 题解:哎.智商是硬伤啊,虽然线段树也做过不少题目,但是遇到这样的题目还是不会处理啊,看了别人的代码才明白了怎么做.用那个线段树维护区间最大前缀,最大后缀,以及真正的最大区间

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 Ray, Pass me the Dishes, LA 3938 , 线段树,区间查询

题意:给出一列数(n个),m次查询区间[l,r]的最大连续区间[x,y](l<=x<=y<=r).(n,m<=500 000) 思路:动态查询区间最大连续区间: 如果是求最大连续区间和: 用线段树维护最大连续和sum_sub.最大前缀和sum_prefix.最大后缀和sum_suffix. root.sum_sub = max{l.sum_sub, r.sum_sub, (l.sum_suffix + r.sum_prefix) }; 题目要求区间,类似的: 用线段树维护最大连续区

UVA-1400 Ray, Pass me the dishes!

UVA-1400 Ray, Pass me the dishes! 题意:给出一个长度为n的整数序列D,有m个询问,每个询问(a,b)找到两个下标x和y,使得a<=x<=y<=n,并且Dx+...+Dy尽量大.如果有多组满足条件的x和y,x应该尽量小.如果还有多解,y应该尽量小. 思路:线段树,对于一个区间,需要维护的值是这个区间的最大连续前缀和,后缀和以及最大连续和的数字下标出现位置.这样,当找(a,b)的最大连续和的下标位置时,分三种情况: 1:最大连续和的起点和终点都在[a,mid

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