The Child and Sequence 题解
题目链接
题目描述
有一个长度为 \(n\) 的数列 \(\{a_n\}\) 和 \(m\) 次操作,操作内容如下:
- 格式为 
1 l r,表示求 \(\sum \limits _{i=l}^{r} a_i\) 的值并输出。 - 格式为 
2 l r x,表示对区间 \([l,r]\) 内每个数取模,模数为 \(x\)。 - 格式为 
3 k x,表示将 \(a_k\) 修改为 \(x\)。 
\(1 \leq n, m \leq 10^5\) , \(1 \leq l, r, k, x, a_i \leq 10^9\)
解题思路
通过题目中两个区间操作不难发现此题需要用 线段树 维护, 本题解着重讲解操作 \(2\)。
- 
对于操作 \(1\) :线段树可以轻松维护区间和的查询和维护。
 - 
对于操作 \(3\) :线段树也支持单点修改。
- 对于操作 \(1\) 和操作 \(3\) ,可以先利用线段树做出 P3374 【模板】树状数组 1 这题,如果实在做不出来 
那你线段树学了个啥可以去参考一下题解 。 
 - 对于操作 \(1\) 和操作 \(3\) ,可以先利用线段树做出 P3374 【模板】树状数组 1 这题,如果实在做不出来 
 - 
对于操作 \(2\) :我们可以探究一下 正整数 之间取模的性质:
- 
我们设 \(p\) 为模数, \(x\) 为被模数,关于 \(x\ \text{mod}\ p\) 的值有以下几点性质:
- 性质 \(1\) :当 \(x < p\) 时:\(x\ \text{mod}\ p = x\) 。
 - 性质 \(2\) :当 \(x \geq p\) 时: \(x\ \text{mod}\ p < \dfrac{x}{2}\) 。
 
所以对于性质 \(1\) 我们发现所有小于模数 \(p\) 的被模数 \(x\) 对答案没有影响,所以我们可以用线段树维护一个区间 \(max\) ,如果区间 \(max\) 大于模数 \(p\) 我们可以选择不修改。对于性质 \(2\) ,每次取模都会使 \(x\) 至少缩减 \(\frac{1}{2}\) ,所以至多修改 \(\log_2 x\) 次,所以对于区间的修改我们以选择暴力的对区间中的每个节点修改。
 - 
对于性质 \(2\) ,我们给出证明:
设 \(x = kp + c\) ,(\(c\) 表示 \(x\ \text{mod}\ p\) 的值,\(p\) 为模数, \(kp\) 表示小于等于 \(x\) 可以被 \(p\) 整除的最大正整数)
根据取模性质得出 \(c < p\) ,又因为 \(p \in \mathbb{N}_+ , kp \in \mathbb{N}_+\) ,所以 \(k \in \mathbb{N}_+\) ,所以 \(k \geq 1\) 。
然后我们就得出以下式子:
 
 - 
 
代码:
#include <bits/stdc++.h>
const int N = 100010;
int n, m;
long long a[N];
class SegmentTree {
public:
	void pushup(int p) {
		t[p].sum = t[p << 1].sum + t[(p << 1) + 1].sum;
		t[p].max = std::max(t[p << 1].max, t[(p << 1) + 1].max);
	}
	void build(int p, int l, int r) {
		t[p].l = l;
		t[p].r = r;
		if (l == r) {
			t[p].sum = a[l];
			t[p].max = a[l];
			return;
		}
		int mid = (t[p].l + t[p].r) >> 1;
		build(p << 1, l, mid);
		build((p << 1) + 1, mid + 1, r);
		pushup(p);
	}
	void change_cover(int p, int x, long long k) {
		if (t[p].l == t[p].r) {
			t[p].sum = k;
			t[p].max = k;
			return;
		}
		int mid = (t[p].l + t[p].r) >> 1;
		if (x <= mid) change_cover(p << 1, x, k);
		else change_cover((p << 1) + 1, x, k);
		pushup(p);
	}
	void change_mod(int p, int l, int r, long long k) {
		if (t[p].max < k) return;
		if (t[p].l == t[p].r) {
			t[p].sum %= k;
			t[p].max %= k;
			return;
		}
		int mid = (t[p].l + t[p].r) >> 1;
		if (l <= mid) change_mod(p << 1, l, r, k);
		if (r > mid) change_mod((p << 1) + 1, l, r, k);
		pushup(p);
	}
	long long ask(int p, int l, int r) {
		if (l <= t[p].l && r >= t[p].r)
			return t[p].sum;
		long long sum = 0;
		int mid = (t[p].l + t[p].r) >> 1;
		if (l <= mid) sum += ask(p << 1, l, r);
		if (r > mid) sum += ask((p << 1) + 1, l, r);
		return sum;
	}
private:
	struct point {
		int l, r;
		long long sum, max;
	} t[N << 2];
} t;
int main() {
	scanf("%d%d", &n, &m);
	for (int i = 1; i <= n; i++)
		scanf("%lld", &a[i]);
	t.build(1, 1, n);
	while (m--) {
		int op;
		scanf("%d", &op);
		if (op == 1) {
			int l, r;
			scanf("%d%d", &l, &r);
			printf("%lld\n", t.ask(1, l, r));
		} else if (op == 2) {
			long long k;
			int l, r;
			scanf("%d%d%lld", &l, &r, &k);
			t.change_mod(1, l, r, k);
		} else {
			int k;
			long long x;
			scanf("%d%lld", &k, &x);
			t.change_cover(1, k, x);
		}
	}
	return 0;
}

                
            
        
浙公网安备 33010602011771号