1. 程式人生 > >HDU 5316 線段樹 單點更新 區間最值

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 <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; }