1. 程式人生 > 其它 >線段樹區間取膜438D - The Child and Sequence

線段樹區間取膜438D - The Child and Sequence

438D - The Child and Sequence

題面

長度為n的非負整數數列,3種操作

  1. \([L,R]\)所有數的和。
  2. \([L,R]\)中所有數都\(mod \ x\)
  3. \(a_i\)修改為\(v\)
    \(n,m≤100000\)

題解

對於一段區間,如果取模的數比這段區間所有的數都大,那取模就是沒有意義的,就是說,如果取模的數比區間最大的數還大,那麼就不用取模了,所以我們線上段樹裡再記錄一個區間最大值

考慮每次取模,對於每一個數\(x\),取模\(y\)\(x \ mod \ y\)的值必然比\(y\)小,如果\(y\)小於\(\frac{x}{2}\),那x就變得小於\(\frac{x}{2}\)

,如果\(y\)大於\(\frac{x}{2}\)\(x\)剩下的部分也比\(\frac{x}{2}\)少,\(x\)也會變得比\(\frac{x}{2}\)

那麼就是說\(x\)每次取模都會變得比\(\frac{x}{2}\)小,就是說,對於一個數\(x\),有效的取\(mod\)最多進行\(logx\)次,一共只會進行\(nlogn\)次取模,那麼就算對所有的數取模,這個時間複雜度都是可以接受的

那麼我們對於每個區間記錄一個最大值,如果取模的數大於最大值,就不管,如果小於最大值,就暴力取模

程式碼

struct BIT {
    struct node {
        int l, r;
        long long sum;
        int mx;
    } tr[N << 2];
    void push_up(int p) {
        tr[p].mx = max(tr[p << 1].mx, tr[p << 1 | 1].mx);
        tr[p].sum = tr[p << 1].sum + tr[p << 1 | 1].sum;
    }
    void build(int p, int l, int r, vector<int>& a) {
        tr[p].l = l, tr[p].r = r;
        if (l == r) {
            tr[p].sum = tr[p].mx = a[l];
            return;
        }
        int mid = l + r >> 1;
        build(p << 1, l, mid, a);
        build(p << 1 | 1, mid + 1, r, a);
        push_up(p);
    }
    int ask(int p, int l, int r) {
        if (tr[p].l >= l && tr[p].r <= r)
            return tr[p].sum;
        int mid = tr[p].l + tr[p].r >> 1;
        if (mid >= r)
            return ask(p << 1, l, r);
        if (mid < l)
            return ask(p << 1 | 1, l, r);
        return ask(p << 1, l, r) + ask(p << 1 | 1, l, r);
    }
    void change(int p, int k, int v) {
        if (tr[p].l == k && tr[p].r == k) {
            tr[p].sum = tr[p].mx = v;
            return;
        }
        int mid = tr[p].l + tr[p].r >> 1;
        if (mid >= k)
            change(p << 1, k, v);
        else if (mid < k)
            change(p << 1 | 1, k, v);
        push_up(p);
    }
    void changemod(int p, int l, int r, int mod) {
        if (tr[p].l == tr[p].r) {
            tr[p].sum = tr[p].mx = tr[p].sum % mod;
            return;
        }
        int mid = tr[p].l + tr[p].r >> 1;
        if (mid >= l && tr[p << 1].mx >= mod)
            changemod(p << 1, l, r, mod);
        if (mid < r && tr[p << 1 | 1].mx >= mod)
            changemod(p << 1 | 1, l, r, mod);
        push_up(p);
    }
} bit;

int main() {
    ios::sync_with_stdio(0);
    cin.tie(0), cout.tie(0);

    int n, m;
    cin >> n >> m;

    vector<int> a(n + 1);
    for (int i = 1; i <= n; ++i)
        cin >> a[i];
    bit.build(1, 1, n, a);

    while (m--) {
        int op;
        cin >> op;
        if (op == 1) {
            int l, r;
            cin >> l >> r;
            cout << bit.ask(1, l, r) << '\n';
        } else if (op == 2) {
            int l, r, mod;
            cin >> l >> r >> mod;
            bit.changemod(1, l, r, mod);
        } else {
            int k, v;
            cin >> k >> v;
            bit.change(1, k, v);
        }
    }
    return 0;
}