【JZOJ 1384】Alice的游戏
题目大意:
有 \(n\) 个数,\(m\) 个操作,每个操作都给定一个区间、两个步骤,查询区间和与区间加一(即 \(0\leq i\leq 8\) 时 \(i\leftarrow i+1\),否则 \(i\leftarrow 0\))。
正文:
因为是区间操作所以考虑线段树。可以开两个线段树,一个存区间和,另一个存区间内\(0\ldots 9\) 的数量。本题的难点主要在于 Lazy 标记,变形时建议开个工具数组。
int tool[11];
void spreadd(int x)
{
for(int i = 0; i <= 9; i++)
{
tool[(i + sgt[x].dif) % 10] = val[x][i];
}
sgt[x].val = 0;
for(int i = 0; i <= 9; i++)
{
val[x][i] = tool[i];
sgt[x].val += val[x][i] * i;
}
sgt[x].dif = 0;
}
void spread(int x) {
if(sgt[x].lzy) {
sgt[x << 1].lzy += sgt[x].lzy;
sgt[x << 1 | 1].lzy += sgt[x].lzy;
sgt[x << 1].dif += sgt[x].lzy;
sgt[x << 1 | 1].dif += sgt[x].lzy;
sgt[x].lzy = 0;
spreadd(x << 1);
spreadd(x << 1 | 1);
spreadd(x);
}
}
全部代码:
const int N = 250010;
int n, m;
int a[N];
struct SegmentTree {
int l, r;
int val, lzy, dif;
} sgt[N << 2];
int val[N << 2][10];
inline void opt(int x) {
sgt[x].val = sgt[x << 1].val + sgt[x << 1 | 1].val;
for(register int i = 0; i <= 9; ++i) {
val[x][i] = val[x << 1][i] + val[x << 1 | 1][i];
}
}
void build(int x, int l, int r) {
sgt[x].l = l, sgt[x].r = r;
if(l == r) {
sgt[x].val = a[l];
++val[x][a[l]];
return ;
}
int mid = (sgt[x].l + sgt[x].r) / 2;
build(x << 1, l, mid);
build(x << 1 | 1, mid + 1, r);
opt(x);
}
int tool[11];
void spreadd(int x)
{
for(int i = 0; i <= 9; i++)
{
tool[(i + sgt[x].dif) % 10] = val[x][i];
}
sgt[x].val = 0;
for(int i = 0; i <= 9; i++)
{
val[x][i] = tool[i];
sgt[x].val += val[x][i] * i;
}
sgt[x].dif = 0;
}
void spread(int x) {
if(sgt[x].lzy) {
sgt[x << 1].lzy += sgt[x].lzy;
sgt[x << 1 | 1].lzy += sgt[x].lzy;
sgt[x << 1].dif += sgt[x].lzy;
sgt[x << 1 | 1].dif += sgt[x].lzy;
sgt[x].lzy = 0;
spreadd(x << 1);
spreadd(x << 1 | 1);
spreadd(x);
}
}
int search(int x, int l, int r) {
if(l <= sgt[x].l && sgt[x].r <= r) {
return sgt[x].val;
}
spread(x);
int mid = (sgt[x].l + sgt[x].r) / 2;
if(mid < l) return search(x << 1 | 1, l, r);
if(mid >= r) return search(x << 1, l, r);
return search(x << 1, l, mid) + search(x << 1 | 1, mid + 1, r);
}
void change(int x, int l, int r)
{
if(l == sgt[x].l && r == sgt[x].r)
{
sgt[x].lzy++;
sgt[x].dif++;
spreadd(x);
return;
}
spread(x);
int mid = (sgt[x].l + sgt[x].r) / 2;
bool flag = 1;
if(mid < l) change(x << 1 | 1, l, r), flag=0;
if(mid >= r) change(x << 1, l, r), flag=0;
if(flag) {
change(x << 1, l, mid);
change(x << 1 | 1, mid + 1, r);
}
opt(x);
}
int main() {
// freopen(".in", "r", stdin);
// freopen(".out", "w", stdout);
scanf("%d%d", &n, &m);
char c = getchar();
while(c < '0' || c > '9') c = getchar();
for(int i = 1; i <= n; i++) {
a[i] = c - '0';
c = getchar();
}
build(1, 1, n);
for(register int i = 1; i <= m; i++) {
int l, r;
scanf("%d%d", &l, &r);
printf("%d\n", search(1, l, r));
change(1, l, r);
}
return 0;
}