HDU 5316 Magician

来源:互联网 发布:淘宝网店团队架构 编辑:程序博客网 时间:2024/04/29 19:11

problem


题意

  • 给定一组序列和一些操作。有两种操作,一个操作是修改序列中一个位置的值,另外一个操作是统计一个区间上beatuiful subsequence的最大和。beatuiful subsequence是一个子序列,其相邻的序列编号奇偶不同。

思路

  • 用线段树来处理,每个节点存一个sum[4]及区间长度,前一位代表选出序列开头离区间左边的奇偶性,后一位代表代表选出序列结尾离区间右边的奇偶性。
  • 合并时方程如下
long long r[4];for (int i = 0; i < 4; i++){    r[i] = std::max(    std::max(sum[i & 2] + x.sum[i & 1],    sum[(i & 2) | 1] + x.sum[(i & 1) | 2]),    std::max(sum[i ^ (x.len & 1)], x.sum[i ^ ((len & 1) << 1)]));}
  • 然后就按照线段树正常写就可以了。(再次膜拜jiefangxuanyan的线段树)

AC代码

HDU5316

#include <cstdio>#include <cstring>#include <algorithm>const int N = 110000, NINF = -N * 1000000000ll;struct rec{    long long sum[4];    int len;    rec(int num) :len(1){        sum[0] = num;        for (int i = 1; i < 4; i++){            sum[i] = NINF;        }    }    rec() :len(0){        for (int i = 0; i < 4; i++){            sum[i] = NINF;        }    }    rec(const long long *s, int len) :len(len){        memcpy(sum, s, sizeof(sum));    }    rec operator+(const rec &x)const{        long long r[4];        for (int i = 0; i < 4; i++){            r[i] = std::max(                std::max(sum[i & 2] + x.sum[i & 1],                sum[(i & 2) | 1] + x.sum[(i & 1) | 2]),                std::max(sum[i ^ (x.len & 1)], x.sum[i ^ ((len & 1) << 1)]));        }        return rec(r, len + x.len);    }}t[4 * N];void set(unsigned pos, int num){    t[pos] = rec(num);    while (pos >> 1){        t[pos >> 1] = t[pos&(~1u)] + t[pos | 1u];        pos >>= 1;    }}rec get(unsigned pos, unsigned l, unsigned r, int lv){    unsigned lb = pos << lv, rb = (pos + 1) << lv;    if (rb <= l || r <= lb){        return rec();    }    if (l <= lb&&rb <= r){        return t[pos];    }    return get(pos << 1, l, r, lv - 1) + get((pos << 1) | 1, l, r, lv - 1);}int main(){    int cn;    scanf("%d", &cn);    for (int ci = 0; ci < cn; ci++){        int n, q;        scanf("%d%d", &n, &q);        int lv = 0;        while ((1 << lv) <= n){            lv++;        }        for (int i = 0; i < n; i++){            int a;            scanf("%d", &a);            set(i + (1 << lv), a);        }        for (int i = 0; i < q; i++){            int op;            scanf("%d", &op);            if (op){                int pos, a;                scanf("%d%d", &pos, &a);                pos--;                set(pos + (1 << lv), a);            } else{                int l, r;                scanf("%d%d", &l, &r);                l--;                rec got = get(1, l + (1 << lv), r + (1 << lv), lv);                long long s = NINF;                for (int i = 0; i < 4; i++){                    s = std::max(got.sum[i], s);                }                printf("%I64d\n", s);            }        }    }    return 0;}
0 0