CF920F SUM and REPLACE 题解

线段树好题。

首先,如果做过 P4145 上帝造题的七分钟2 / 花神游历各国 ,那么这道题还是十分好想的。

我们需要意识到一个问题:对于 \(1,2\) 这两个数而言,我们对它们修改是没有意义的,\(1\) 还是 \(1\)\(2\) 还是 \(2\)

那么我们再想想,对于 \(a_i\) 几次操作之后就会变成 \(1,2\) 呢?

我们可以 使用数学方法 打一个暴力程序算一算,发现最多不超过 6 次。

于是这不就变成上面那道题了吗?

我们先预处理出 \(d_i\),然后线段树维护两个值 \(sum,max\),在修改操作的时候如果 \(max\)\(1\)\(2\),那么跳过不修改;否则直接暴力修改即可。

代码:

#include <bits/stdc++.h>
using namespace std;

typedef long long LL;
LL Max(LL fir, LL sec) {return (fir > sec) ? fir : sec;}

const int MAXN = 3e5 + 10, MAXA = 1e6 + 10;
int n, m, a[MAXN], cnt[MAXA];
struct node
{
	int l, r;
	LL sum, maxn;
	#define l(p) tree[p].l
	#define r(p) tree[p].r
	#define s(p) tree[p].sum
	#define m(p) tree[p].maxn
}tree[MAXN << 2];

int read()
{
	int sum = 0, fh = 1; char ch = getchar();
	while (ch < '0' || ch > '9') {if (ch == '-') fh = -1; ch = getchar();}
	while (ch >= '0' && ch <= '9') {sum = (sum << 3) + (sum << 1) + (ch ^ 48); ch = getchar();}
	return sum * fh;
}

void build(int p, int l, int r)
{
	l(p) = l, r(p) = r;
	if (l == r) {s(p) = m(p) = a[l]; return ;}
	int mid = (l(p) + r(p)) >> 1;
	build(p << 1, l, mid); build(p << 1 | 1, mid + 1, r);
	s(p) = s(p << 1) + s(p << 1 | 1);
	m(p) = Max(m(p << 1), m(p << 1 | 1));
}

void change(int p, int l, int r)
{
	if (l(p) == r(p)) {s(p) = m(p) = cnt[s(p)]; return ;}
	if (m(p) == 2 || m(p) == 1) return ;
	int mid = (l(p) + r(p)) >> 1;
	if (l <= mid) change(p << 1, l, r);
	if (r > mid) change(p << 1 | 1, l, r);
	s(p) = s(p << 1) + s(p << 1 | 1);
	m(p) = Max(m(p << 1), m(p << 1 | 1));
}

LL ask(int p, int l, int r)
{
	if (l(p) >= l && r(p) <= r) return s(p);
	int mid = (l(p) + r(p)) >> 1; LL val = 0;
	if (l <= mid) val += ask(p << 1, l, r);
	if (r > mid) val += ask(p << 1 | 1, l, r);
	return val;
}

int main()
{
	n = read(), m = read();
	for (int i = 1; i <= n; ++i) a[i] = read();
	build(1, 1, n);
	for (int i = 1; i <= 1000000; ++i)
		for (int j = i; j <= 1000000; j += i)
			cnt[j]++;
	for (int i = 1; i <= m; ++i)
	{
		int opt = read(), l = read(), r = read();
		if (opt == 1) change(1, l, r);
		else printf("%lld\n", ask(1, l, r));
	}
	return 0;
}
posted @ 2022-04-14 20:33  Plozia  阅读(35)  评论(0编辑  收藏  举报