给一个序列,有n位,下标索引为[1,n],有两种操作:
"1,2,3,4,5,6,7,8,9"
,那么子序列可以为"1,4,5,6,7,8,9"
或者"4,1,5,6,7,8,9"
,等等。其实这种全排列是没用的,因为题目让我们求得是累加和,全排列其实代表的是一种。明显是线段树的单点更新,区间最值。区间最值求的是累加和,但是我们怎么处理奇偶交替呢?我们可以转化问题:把每一个子序列分四类:
这样我们在区间合并的时候可以分四类,往上合并,然后查询求区间最值的时候,可以取四种情况中的最大值。
#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;
}