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