题意
- 给定一组序列和一些操作。有两种操作,一个操作是修改序列中一个位置的值,另外一个操作是统计一个区间上
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;
}