很不错的线段树题。
#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
using namespace std;
const int maxn = 100010;
int tcase, n, q;
int a[maxn];
/*
ldr: 从区间左端点开始的前n项和的数字根的二进制表示
rdr: 从区间右端点开始的后n项和的数字根的二进制表示
idr: 区间内所有子区间和的数字根的二进制表示
sum: 区间和的数字根
*/
int ldr[maxn<<2], rdr[maxn<<2], idr[maxn<<2], sum[maxn<<2];
/*询问时用到的结构体*/
struct Node {
int ldr, rdr, idr, sum;
Node() {
ldr = rdr = idr = sum = 0;
}
};
inline int digroot(int x)
{ // 求数字根
return (x - 1) % 9 + 1;
}
inline void pushUp(int rt)
{
int lson = rt << 1, rson = rt << 1 | 1;
sum[rt] = digroot(sum[lson] + sum[rson]);
ldr[rt] |= ldr[lson];
rdr[rt] |= rdr[rson];
idr[rt] |= idr[lson];
idr[rt] |= idr[rson];
idr[rt] |= (1 << sum[rt]);
for (int i = 0; i < 10; ++i) {
if (ldr[rson] & (1 << i)) {
ldr[rt] |= (1 << digroot(sum[lson] + i));
for (int j = 0; j < 10; ++j) {
if (rdr[lson] & (1 << j)) {
idr[rt] |= (1 << digroot(i + j));
}
}
}
if (rdr[lson] & (1 << i)) {
rdr[rt] |= (1 << digroot(sum[rson] + i));
}
}
}
void build(int l, int r, int rt)
{
ldr[rt] = rdr[rt] = idr[rt] = 0;
if (l == r) {
sum[rt] = digroot(a[l]);
ldr[rt] |= (1 << sum[rt]);
rdr[rt] |= (1 << sum[rt]);
idr[rt] |= (1 << sum[rt]);
return ;
}
int m = (l + r) >> 1;
build(l, m, rt << 1);
build(m + 1, r, rt << 1 | 1);
pushUp(rt);
}
void query(int l, int r, int rt, int L, int R, Node& node)
{
if (L <= l && R >= r) {
node.sum = sum[rt];
node.ldr |= ldr[rt];
node.rdr |= rdr[rt];
node.idr |= idr[rt];
return ;
}
int m = (l + r) >> 1;
Node lnode, rnode;
if (R <= m) {
query(l, m, rt << 1, L, R, node);
} else if (L > m) {
query(m + 1, r, rt << 1 | 1, L, R, node);
} else {
query(l, m, rt << 1, L, R, lnode);
query(m + 1, r, rt << 1 | 1, L, R, rnode);
node.sum = digroot(lnode.sum + rnode.sum);
node.ldr |= lnode.ldr;
node.rdr |= rnode.rdr;
node.idr |= (1 << node.sum);
node.idr |= lnode.idr;
node.idr |= rnode.idr;
for (int i = 0; i < 10; ++i) {
if (rnode.ldr & (1 << i)) {
node.ldr |= (1 << digroot(lnode.sum + i));
for (int j = 0; j < 10; ++j) {
if (lnode.rdr & (1 << j)) {
node.idr |= (1 << digroot(i + j));
}
}
}
if (lnode.rdr & (1 << i)) {
node.rdr |= (1 << digroot(rnode.sum + i));
}
}
}
return ;
}
int main()
{
scanf("%d", &tcase);
for (int cas = 1; cas <= tcase; ++cas) {
if (cas != 1) {
printf("\n");
}
printf("Case #%d:\n", cas);
scanf("%d", &n);
for (int i = 1; i <= n; ++i) {
scanf("%d", &a[i]);
}
build(1, n, 1);
scanf("%d", &q);
while (q--) {
int l, r;
Node node;
scanf("%d%d", &l, &r);
query(1, n, 1, l, r, node);
int cnt = 0;
for (int i = 9; i >= 0; --i) {
if (node.idr & (1 << i)) {
if (cnt == 0) {
printf("%d", i);
} else {
printf(" %d", i);
}
cnt++;
if (cnt == 5) break;
}
}
for (int i = cnt; i < 5; ++i) {
if (i == 0) {
printf("-1");
} else {
printf(" -1");
}
}
printf("\n");
}
}
return 0;
}