HDU 5316 線段樹 單點更新 區間最值
阿新 • • 發佈:2019-01-22
傳送門:題目
題意:
給一個序列,有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 <bits/stdc++.h>
#define debug(x) cout<<#x<<" = "<<x<<endl;
#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;
}