HDU 5316 线段树 单点更新 区间最值

传送门:题目

题意:

给一个序列,有n位,下标索引为[1,n],有两种操作:

  • 更改某一位的值
  • 查询区间[l,r]中子序列中所有元素累加和的最大值,这里子序列的定义为:子序列中的下标映射到原序列中,下标可以不相邻,只要满足奇偶交替即可,比如:原序列是"1,2,3,4,5,6,7,8,9",那么子序列可以为"1,4,5,6,7,8,9"或者"4,1,5,6,7,8,9",等等。其实这种全排列是没用的,因为题目让我们求得是累加和,全排列其实代表的是一种。

题解:

明显是线段树的单点更新,区间最值。区间最值求的是累加和,但是我们怎么处理奇偶交替呢?我们可以转化问题:把每一个子序列分四类:

  • 子序列的第一位是对应的下标是奇数,最后一位对应的下标是奇数。
  • 子序列的第一位是对应的下标是偶数,最后一位对应的下标是偶数。
  • 子序列的第一位是对应的下标是奇数,最后一位对应的下标是偶数。
  • 子序列的第一位是对应的下标是偶数,最后一位对应的下标是奇数。

这样我们在区间合并的时候可以分四类,往上合并,然后查询求区间最值的时候,可以取四种情况中的最大值。

AC代码:

#include 
#define debug(x) cout<<#x<<" = "<
#define int long long
using namespace std;

const int maxn = 1e5 + 10;
const long long INF = 0x3f3f3f3f3f3f3f3f;
int val[maxn];
struct EOSET {
    long long oo , ee, oe , eo ;
};
long long four_elements_max(long long a, long long b, long long c, long long d) {
    return max(max(a, b), max(c, d));
}
/******************线段树模板**********************/
EOSET SegTree[maxn << 2];
void BuildTree(int l, int r, int rt) {//建树,lr是总区间,rt是根结点一般为1
    if (l == r) {
        SegTree[rt].eo = SegTree[rt].oe = -INF;
        if (l & 1)
            SegTree[rt].oo = val[l], SegTree[rt].ee = -INF;
        else
            SegTree[rt].ee = val[l], SegTree[rt].oo = -INF;
        return ;
    }
    int m = (l + r) >> 1;
    BuildTree(l, m, rt << 1);
    BuildTree(m + 1, r, rt << 1 | 1);
    SegTree[rt].oo = four_elements_max(SegTree[rt << 1].oo, SegTree[rt << 1 | 1].oo, SegTree[rt << 1].oo + SegTree[rt << 1 | 1].eo, SegTree[rt << 1].oe + SegTree[rt << 1 | 1].oo);
    SegTree[rt].ee = four_elements_max(SegTree[rt << 1].ee, SegTree[rt << 1 | 1].ee, SegTree[rt << 1].ee + SegTree[rt << 1 | 1].oe, SegTree[rt << 1].eo + SegTree[rt << 1 | 1].ee);
    SegTree[rt].eo = four_elements_max(SegTree[rt << 1].eo, SegTree[rt << 1 | 1].eo, SegTree[rt << 1].ee + SegTree[rt << 1 | 1].oo, SegTree[rt << 1].eo + SegTree[rt << 1 | 1].eo);
    SegTree[rt].oe = four_elements_max(SegTree[rt << 1].oe, SegTree[rt << 1 | 1].oe, SegTree[rt << 1].oo + SegTree[rt << 1 | 1].ee, SegTree[rt << 1].oe + SegTree[rt << 1 | 1].oe);
}
EOSET Query(int L, int R, int l, int r, int rt) {//区间查询,LR是查询区间,lr是总区间,rt是根结点一般为1
    if (l >= L && r <= R) {
        EOSET temp;
        temp.oo = SegTree[rt].oo, temp.ee = SegTree[rt].ee, temp.eo = SegTree[rt].eo, temp.oe = SegTree[rt].oe;
        return temp;
    }
    int m = (l + r) >> 1;
    EOSET ans1 , ans2 , temp;
    ans1.oo = -INF, ans1.ee = -INF, ans1.oe = -INF, ans1.eo = -INF;
    ans2.oo = -INF, ans2.ee = -INF, ans2.oe = -INF, ans2.eo = -INF;
    if (L <= m)
        ans1 = Query(L, R, l, m, rt << 1);
    if (R > m)
        ans2 = Query(L, R, m + 1, r, rt << 1 | 1);
    temp.oo = four_elements_max(ans1.oo, ans2.oo, ans1.oe + ans2.oo, ans1.oo + ans2.eo);
    temp.ee = four_elements_max(ans1.ee, ans2.ee, ans1.eo + ans2.ee, ans1.ee + ans2.oe);
    temp.eo = four_elements_max(ans1.eo, ans2.eo, ans1.ee + ans2.oo, ans1.eo + ans2.eo);
    temp.oe = four_elements_max(ans1.oe, ans2.oe, ans1.oo + ans2.ee, ans1.oe + ans2.oe);
    return temp;
}
void Update(int point, long long value, int l, int r, int rt) {//单点更新,把point点的值改为value,lr是总区间,rt是根结点一般为1
    if (l == r) {
        SegTree[rt].eo = SegTree[rt].oe = -INF;
        if (l & 1)
            SegTree[rt].oo = value, SegTree[rt].ee = -INF;
        else
            SegTree[rt].ee = value, SegTree[rt].oo = -INF;
        return ;
    }
    int m = (l + r) >> 1;
    if (point <= m)
        Update(point, value, l, m, rt << 1);
    else
        Update(point, value, m + 1, r, rt << 1 | 1);
    SegTree[rt].oo = four_elements_max(SegTree[rt << 1].oo, SegTree[rt << 1 | 1].oo, SegTree[rt << 1].oo + SegTree[rt << 1 | 1].eo, SegTree[rt << 1].oe + SegTree[rt << 1 | 1].oo);
    SegTree[rt].ee = four_elements_max(SegTree[rt << 1].ee, SegTree[rt << 1 | 1].ee, SegTree[rt << 1].ee + SegTree[rt << 1 | 1].oe, SegTree[rt << 1].eo + SegTree[rt << 1 | 1].ee);
    SegTree[rt].eo = four_elements_max(SegTree[rt << 1].eo, SegTree[rt << 1 | 1].eo, SegTree[rt << 1].ee + SegTree[rt << 1 | 1].oo, SegTree[rt << 1].eo + SegTree[rt << 1 | 1].eo);
    SegTree[rt].oe = four_elements_max(SegTree[rt << 1].oe, SegTree[rt << 1 | 1].oe, SegTree[rt << 1].oo + SegTree[rt << 1 | 1].ee, SegTree[rt << 1].oe + SegTree[rt << 1 | 1].oe);
}
/******************线段树模板**********************/
signed main(void) {
    ios::sync_with_stdio(false);
    int T;
    cin >> T;
    while (T--) {
        int n, m, t1, t2, t3;
        cin >> n >> m;
        for (int i = 1; i <= n; i++)
            cin >> val[i];
        BuildTree(1, n, 1);
        while (m--) {
            cin >> t1 >> t2 >> t3;
            if (t1 == 1)
                Update(t2, t3, 1, n, 1);
            else if (t1 == 0) {
                EOSET ans = Query(t2, t3, 1, n, 1);
                cout << four_elements_max(ans.oo, ans.ee, ans.eo, ans.oe) << endl;
            }
        }
    }
    return 0;
}

你可能感兴趣的:(数据结构)