1. 程式人生 > >Codeforces 1136E(轉化+線段樹維護)

Codeforces 1136E(轉化+線段樹維護)

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(轉化+線段樹維護)