对于这个“好的”的判定条件看起来有点奇怪,不妨结合上题目要求的“最小 \(sum\)”一起考虑。
因为要最小化 \(s_p\),所以一个比较直观的想法是先从选的数个数入手。
考虑到如果选的只有 \(1\) 个数 \(a_i\),那么 \(sum = a_i\),一定是好的,排除。
如果选的是 \(2\) 个数 \(a_i, a_j\),那么有 \(sum = a_i + a_j\)。
考虑到加法可能带有进位的操作,但实际上可以通过从低位到高位来讨论解决:
- 若这一位 \(a_i, a_j\) 均为 \(0\),则这一位一定是好的,那就继续往高位看。
- 若这一位 \(a_i, a_j\) 有一个为 \(0\),那么这一位也是好的,那就继续往高位看。
- 若这一位 \(a_i, a_j\) 均不为 \(0\),那么这一位一定是坏的。
需要注意的是因为是从低位往高位看的,所以下面一定不产生进位,可以暴力枚举每一位的数值,可以知道一定无法匹配上。
于是可以发现的是,只要存在一位满足 \(a_i, a_j\) 在此位均不为 \(0\),那么 \(sum = a_i + a_j\) 就是合法的。
考虑扩展到更多数,能够发现其实越多数限制反而越难满足。
但是此时一个位是坏的肯定也需要满足至少存在一位,非 \(0\) 的个数 \(\ge 2\):
- 如果是因为进位导致这一位变坏,那么有进位也需要下面有位的非 \(0\) 的个数 \(\ge 2\)。
- 如果没有进位,那么只有 \(0, 1\) 个肯定不行,所以肯定需要 \(\ge 2\)。
所以可以发现,选更多的数反而不如就选 \(2\) 个。
那么接下来的问题就变为:
找到 \(l\le i, j\le r\),满足存在一位满足 \(a_i, a_j\) 在此位均不为 \(0\),最小化 \(a_i + a_j\)。
能够发现此时每一位都是独立的,那么就可以对每一个位去做。
对每一位开一个线段树维护这一位非 \(0\) 的数的最大和次大值,修改和查询对于每颗线段树都问一下就可以了。
时间复杂度 \(\mathcal{O}((n + m)\log n\log_10 V)\)。
#include<bits/stdc++.h>
constexpr int inf = 2e9;
constexpr int maxn = 2e5 + 10;
int n, q;
struct node_t {int mn, smn;inline node_t(int mn_ = inf, int smn_ = inf) {mn = mn_, smn = smn_;}inline node_t operator + (const node_t &a) const {if (mn <= a.mn) {return node_t(mn, std::min(smn, a.mn));} else {return node_t(a.mn, std::min(mn, a.smn));}}
};
struct segtr {node_t tr[maxn * 4];inline void update(int x, int y, int k = 1, int l = 1, int r = n) {if (l == r) {return tr[k] = node_t(y), void();}int mid = l + r >> 1;if (x <= mid) update(x, y, k << 1, l, mid);else update(x, y, k << 1 | 1, mid + 1, r);tr[k] = tr[k << 1] + tr[k << 1 | 1];}inline node_t query(int x, int y, int k = 1, int l = 1, int r = n) {if (x <= l && r <= y) return tr[k];int mid = l + r >> 1;if (y <= mid) return query(x, y, k << 1, l, mid);if (x > mid) return query(x, y, k << 1 | 1, mid + 1, r);return query(x, y, k << 1, l, mid) + query(x, y, k << 1 | 1, mid + 1, r);}
} tr[10];
inline void update(int p, int x) {for (int d = 0, x_ = x; d < 10; d++, x_ /= 10) {tr[d].update(p, x_ % 10 ? x : inf);}
}
int main() {scanf("%d%d", &n, &q);for (int i = 1, x; i <= n; i++) {scanf("%d", &x);update(i, x);}for (int op, x, y; q--; ) {scanf("%d%d%d", &op, &x, &y);if (op == 1) {update(x, y);} else {int ans = -1;for (int d = 0; d < 10; d++) {node_t val = tr[d].query(x, y);if (val.smn == inf) continue;int tot = val.mn + val.smn;if (tot < ans || ans == -1) {ans = tot;}}printf("%d\n", ans);}}return 0;
}