Codeforces 1136E(轉化+線段樹維護)
阿新 • • 發佈:2019-04-07
str out n) == ali inf stream odi names
題目傳送
雖然線段樹比較顯然但是發現a數組並不好維護。考慮將a轉化為好維護的數組b。
方法
這裏我將k[1]設為0,對應著\[a[1] + k[1] <= a[2]\]不難得出\[a[i] + k[i] <= a[i+1]\]
\[a[i]+k[i]+k[i+1] <=a[i+2]\]
所以設\[a[i] = b[i] + t[i],其中t[i]為k[i]的前綴和\]
以樣例來說話:
pos | 1 | 2 | 3 |
---|---|---|---|
a | 1 | 2 | 3 |
k | 0 | 1 | -1 |
t | 0 | 1 | 0 |
b | 1 | 1 | 3 |
可以發現b數組是一個不下降的序列,原因是b是以a[1]為基石的,無論t數組是正是負,只會影響a數組的升降。這樣我們就可以選擇用線段樹維護b,對於‘+‘操作,相當於修改線段樹上的b數組:
1.在b[i]的位置加上x:
ll k = T.Query(i, i, 1) + x;
2.找到小於“修改後的b[i]”的第一個位置,因為只要保持b不下降就可以了,大於等於這個b[i]的位置不修改:
int pos = T.Position(i, n, 1, k);
3.區間修改:
T.Modify(i, pos, 1, k);
對於詢問操作,就不難得出:\[\sum_{i = l}^ra[i] = \sum_{i = l}^r b[i]+t[i]\]
所以求t[i]時順手求個t[i]的前綴和,這道題就完成了。
最後註意線段樹的tag,要設成-inf,這題的數組值是正負皆可的,不能用是否為0來判斷tag:
void Push_down(int p) {
if (t[p].tag > -INF) {
最終代碼:
#include <cstdio> #include <cstring> #include <iostream> #include <algorithm> using namespace std; typedef long long ll; const int maxn = 1e5 + 5; const ll INF = 1e18; int n, q; ll a[maxn], k[maxn], t[maxn], sum[maxn], b[maxn]; class SegmentTree { public: #define ls(p) p << 1 #define rs(p) p << 1 | 1 struct Node { int l, r; ll minn, sum, tag = -INF; }t[maxn << 2]; void Push_up(int p) { t[p].minn = min(t[ls(p)].minn, t[rs(p)].minn); t[p].sum = t[ls(p)].sum + t[rs(p)].sum; } void Push_down(int p) { if (t[p].tag > -INF) { t[ls(p)].minn = t[rs(p)].minn = t[ls(p)].tag = t[rs(p)].tag = t[p].tag; t[ls(p)].sum = t[p].tag * (t[ls(p)].r - t[ls(p)].l + 1); t[rs(p)].sum = t[p].tag * (t[rs(p)].r - t[rs(p)].l + 1); t[p].tag = -INF; } } void Build(int l, int r, int p) { t[p].l = l, t[p].r = r; if (l == r) { t[p].minn = t[p].sum = b[l]; return; } int mid = (l + r) >> 1; Build(l, mid, ls(p)); Build(mid + 1, r, rs(p)); Push_up(p); } void Modify(int l, int r, int p, ll k) { if (l <= t[p].l && t[p].r <= r) { t[p].minn = t[p].tag = k; t[p].sum = k * (t[p].r - t[p].l + 1); return; } int mid = (t[p].l + t[p].r) >> 1; Push_down(p); if (l <= mid) Modify(l, r, ls(p), k); if (mid < r) Modify(l, r, rs(p), k); Push_up(p); } int Position(int l, int r, int p, ll k) { if (t[p].minn < k && t[p].l == t[p].r) return t[p].l; int mid = (t[p].l + t[p].r) >> 1; Push_down(p); if (t[rs(p)].minn < k) return Position(l, r, rs(p), k); else return Position(l, r, ls(p), k); } ll Query(int l, int r, int p) { if (l <= t[p].l && t[p].r <= r) return t[p].sum; int mid = (t[p].l + t[p].r) >> 1; Push_down(p); if (l > mid) return Query(l, r, rs(p)); if (r <= mid) return Query(l, r, ls(p)); return Query(l, r, ls(p)) + Query(l, r, rs(p)); } }T; int main(int argc, char const *argv[]) { ios_base::sync_with_stdio(0); cin.tie(0), cout.tie(0); cin >> n; for (int i = 1; i <= n; i++) cin >> a[i]; for (int i = 2; i <= n; i++) cin >> k[i], t[i] = t[i - 1] + k[i], sum[i] = sum[i - 1] + t[i]; for (int i = 1; i <= n; i++) b[i] = a[i] - t[i]; T.Build(1, n, 1); for (cin >> q; q; q--) { string op; cin >> op; if (op == "+") { int i, x; cin >> i >> x; ll k = T.Query(i, i, 1) + x; int pos = T.Position(i, n, 1, k); T.Modify(i, pos, 1, k); } else { int l, r; cin >> l >> r; cout << T.Query(l, r, 1) + sum[r] - sum[l - 1] << endl; } } return 0; }
Codeforces 1136E(轉化+線段樹維護)