Skip to content

http://poj.openjudge.cn/practice/C26A/

c++
#include <bits/stdc++.h>
using namespace std;

const int MAXN = 100000 + 5;
const int ROOT[9] = {9, 1, 2, 3, 4, 5, 6, 7, 8};

struct Info {
    long long ans;
    int suf[9];   // suf[r]: product mod 9 == r 的后缀数量
    int pre[9];   // pre[k]: 所有前缀 P 的 sum rt(k * product(P))
    int prod;     // 整段乘积 mod 9
};

struct Node {
    Info f[9];    // f[t]: 整段每个元素额外乘以 t 后的信息
    int lazy;     // 懒标记:整段待乘的值 mod 9
};

static Node seg[MAXN * 4];
static int a[MAXN];

inline Info mergeInfo(const Info &L, const Info &R) {
    Info C;

    C.ans = L.ans + R.ans;

    // 跨越左右两段的子数组
    for (int s = 0; s < 9; ++s) {
        C.ans += 1LL * L.suf[s] * R.pre[s];
    }

    C.prod = L.prod * R.prod % 9;

    // 合并前缀打分函数
    for (int k = 0; k < 9; ++k) {
        C.pre[k] = L.pre[k] + R.pre[k * L.prod % 9];
    }

    // 合并后缀数量
    for (int r = 0; r < 9; ++r) {
        C.suf[r] = R.suf[r];
    }

    for (int r = 0; r < 9; ++r) {
        C.suf[r * R.prod % 9] += L.suf[r];
    }

    return C;
}

inline void makeLeaf(Info &x, int residue) {
    x.ans = ROOT[residue];
    x.prod = residue;

    for (int i = 0; i < 9; ++i) {
        x.suf[i] = 0;
    }

    x.suf[residue] = 1;

    for (int k = 0; k < 9; ++k) {
        x.pre[k] = ROOT[k * residue % 9];
    }
}

inline void pull(int p) {
    for (int t = 0; t < 9; ++t) {
        seg[p].f[t] = mergeInfo(seg[p << 1].f[t], seg[p << 1 | 1].f[t]);
    }

    seg[p].lazy = 1;
}

void build(int p, int l, int r) {
    seg[p].lazy = 1;

    if (l == r) {
        for (int t = 0; t < 9; ++t) {
            makeLeaf(seg[p].f[t], a[l] * t % 9);
        }
        return;
    }

    int mid = (l + r) >> 1;
    build(p << 1, l, mid);
    build(p << 1 | 1, mid + 1, r);
    pull(p);
}

inline void applyMul(int p, int mul) {
    if (mul == 1) return;

    Info tmp[9];

    for (int t = 0; t < 9; ++t) {
        tmp[t] = seg[p].f[t * mul % 9];
    }

    for (int t = 0; t < 9; ++t) {
        seg[p].f[t] = tmp[t];
    }

    seg[p].lazy = seg[p].lazy * mul % 9;
}

inline void push(int p) {
    int z = seg[p].lazy;

    if (z != 1) {
        applyMul(p << 1, z);
        applyMul(p << 1 | 1, z);
        seg[p].lazy = 1;
    }
}

void update(int p, int l, int r, int ql, int qr, int mul) {
    if (ql <= l && r <= qr) {
        applyMul(p, mul);
        return;
    }

    push(p);

    int mid = (l + r) >> 1;

    if (ql <= mid) {
        update(p << 1, l, mid, ql, qr, mul);
    }

    if (qr > mid) {
        update(p << 1 | 1, mid + 1, r, ql, qr, mul);
    }

    pull(p);
}

Info query(int p, int l, int r, int ql, int qr) {
    if (ql <= l && r <= qr) {
        return seg[p].f[1];
    }

    push(p);

    int mid = (l + r) >> 1;

    if (qr <= mid) {
        return query(p << 1, l, mid, ql, qr);
    }

    if (ql > mid) {
        return query(p << 1 | 1, mid + 1, r, ql, qr);
    }

    Info L = query(p << 1, l, mid, ql, qr);
    Info R = query(p << 1 | 1, mid + 1, r, ql, qr);

    return mergeInfo(L, R);
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    int n, q;
    cin >> n >> q;

    for (int i = 1; i <= n; ++i) {
        long long x;
        cin >> x;
        a[i] = int(x % 9);
    }

    build(1, 1, n);

    while (q--) {
        int op, l, r;
        cin >> op >> l >> r;

        if (op == 1) {
            long long x;
            cin >> x;
            update(1, 1, n, l, r, int(x % 9));
        } else {
            cout << query(1, 1, n, l, r).ans << '\n';
        }
    }

    return 0;
}