SPOJ 2916 Can you answer these queries V

SPOJ_2916

    这个题目需要分情况讨论一下,如果y1<x2,那么就是前面区间的一个后缀,加上后面区间的一个前缀,再加上中间的部分,如果y1>=x2,则根据位置的不同又可以另分三种情况,逐一讨论并更新最优解即可。

    分析之后就发现,在线段树的基础上写两个查询函数即可,一个就是和SPOJ_1716的GSS1那样功能的函数(在我的程序里面对应的是query这个函数),另一个是可以求一个区间最大的前缀和或者后缀和的函数(在我的程序里面对应的是Search这个函数)。

#include<stdio.h>
#include<string.h>
#define INF 0x3f3f3f3f
#define MAXD 10010
int N, A[MAXD], a[MAXD], mc[4 * MAXD], lc[4 * MAXD], rc[4 * MAXD];
int Max(int x, int y)
{
    return x > y ? x : y;
}
void update(int cur, int x, int y)
{
    int mid = (x + y) >> 1, ls = cur << 1, rs = cur << 1 | 1;
    mc[cur] = Max(mc[ls], mc[rs]);
    mc[cur] = Max(mc[cur], rc[ls] + lc[rs]);
    lc[cur] = Max(lc[ls], A[mid] - A[x - 1] + lc[rs]);
    rc[cur] = Max(rc[rs], A[y] - A[mid] + rc[ls]);
}
void build(int cur, int x, int y)
{
    int mid = (x + y) >> 1, ls = cur << 1, rs = cur << 1 | 1;
    if(x == y)
    {
        mc[cur] = lc[cur] = rc[cur] = a[x];
        return ;
    }
    build(ls, x, mid);
    build(rs, mid + 1, y);
    update(cur, x, y);
}
int query(int cur, int x, int y, int s, int t, int flag, int &ans)
{
    int mid = (x + y) >> 1, ls = cur << 1, rs = cur << 1 | 1;
    if(x >= s && y <= t)
    {
        ans = Max(ans, mc[cur]);
        if(flag == 0)
            return lc[cur];
        else
            return rc[cur];
    }
    if(mid >= t)
        return query(ls, x, mid, s, t, 0, ans);
    else if(mid + 1 <= s)
        return query(rs, mid + 1, y, s, t, 1, ans);
    int ln, rn;
    ln = query(ls, x, mid, s, t, 1, ans);
    rn = query(rs, mid + 1, y, s, t, 0, ans);
    ans = Max(ans, ln + rn);
    if(flag == 0)
        return Max(lc[ls], A[mid] - A[x - 1] + rn);
    else
        return Max(rc[rs], A[y] - A[mid] + ln);
}
void Search(int cur, int x, int y, int s, int t, int flag, int &ans)
{
    int mid = (x + y) >> 1, ls = cur << 1, rs = cur << 1 | 1;
    if(x >= s && y <= t)
    {
        if(flag == 0)
            ans = Max(ans, A[x - 1] - A[s - 1] + lc[cur]);
        else
            ans = Max(ans, A[t] - A[y] + rc[cur]);
        return ;
    }
    if(mid >= s)
        Search(ls, x, mid, s, t, flag, ans);
    if(mid + 1 <= t)
        Search(rs, mid + 1, y, s, t, flag, ans);
}
void init()
{
    int i, j, k;
    scanf("%d", &N);
    A[0] = 0;
    for(i = 1; i <= N; i ++)
    {
        scanf("%d", &a[i]);
        A[i] = A[i - 1] + a[i];
    }
    build(1, 1, N);
}
void solve()
{
    int i, q, ans, t1, t2, x1, y1, x2, y2;
    scanf("%d", &q);
    for(i = 0; i < q; i ++)
    {
        scanf("%d%d%d%d", &x1, &y1, &x2, &y2);
        if(y1 < x2)
        {
            t1 = t2 = -INF;
            Search(1, 1, N, x1, y1, 1, t1);
            Search(1, 1, N, x2, y2, 0, t2);
            printf("%d\n", t1 + t2 + A[x2 - 1] - A[y1]);
        }
        else
        {
            ans = -INF;
            query(1, 1, N, x2, y1, 0, ans);
            t1 = t2 = -INF;
            Search(1, 1, N, x1, y1, 1, t1);
            Search(1, 1, N, y1, y2, 0, t2);
            ans = Max(ans, t1 + t2 - a[y1]);
            t1 = t2 = -INF;
            Search(1, 1, N, x1, x2, 1, t1);
            Search(1, 1, N, x2, y2, 0, t2);
            ans = Max(ans, t1 + t2 - a[x2]);
            printf("%d\n", ans);
        }
    }
}
int main()
{
    int t;
    scanf("%d", &t);
    while(t --)
    {
        init();
        solve();
    }
    return 0;
}

你可能感兴趣的:(poj)