【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;
}
posted @ 2020-03-29 23:23  Jayun  阅读(94)  评论(0编辑  收藏  举报