CF920F SUM and REPLACE
题意:
给定 \(n\) 个数的数组 \(a\),\(m\) 次操作。操作有两种:
- 将 \(i\in[l,r]\) 中的所有 \(a_i\) 替换为 \(d(a_i)\)。\(d(x)\) 表示 \(x\) 的正约数的个数。
- 求 \(\displaystyle\sum_{i=l}^r a_i\)。
首先\(d\)是可以预处理出来的qwq。比如通过线性筛。
线性筛太麻烦了有这样一种预处理方式:
for(int i = 1; i <= 1000000; i ++){
for(int j = i; j <= 1000000; j += i){
d[j] ++;
}
}
实践证明它是不会T的。
然后我们通过观察显然可以发现,在进行好多次操作之后,每个数会一直是\(1\)或\(2\)。
所以对于一个数我们直接暴力修改。毕竟最多的修改次数不会超过\(6\)次。
在维护区间和的同时维护一个区间最大值。
当修改过程中某个区间最大值小于等于\(2\)的时候,说明我们这次的操作是无能的无效的,直接返回即可。
注意要开long long,不然会爆掉orz。所以直接define int long long。
时间复杂度\(O(mlogn)\)。
代码:
#include <bits/stdc++.h>
#define ls (now << 1)
#define rs (now<<1|1)
#define mid ((l+r)>>1)
#define int long long
using namespace std;
const int maxn = 3e5+10;
int n, m, a[maxn], d[1000010];
struct seg_tree{
struct nodes{
int l, r, sum, max_num;
}node[maxn<<2];
void up(int now){return (void)(node[now].sum = node[ls].sum + node[rs].sum, node[now].max_num = max(node[ls].max_num, node[rs].max_num));}
void build(int l, int r, int now){
node[now].l = l, node[now].r = r;
if(l == r) return (void)(node[now].sum = a[l], node[now].max_num = a[l]);
build(l, mid, ls), build(mid+1, r, rs);
return up(now);
}
void chenge(int l, int r, int now){
if(r < node[now].l or node[now].r < l or node[now].max_num <= 2) return;
if(node[now].l == node[now].r) return(void) (node[now].max_num = node[now].sum = d[node[now].sum]);
chenge(l, r, ls), chenge(l, r, rs);
return up(now);
}
void quary(int l, int r, int now, int &ans){
if(r < node[now].l or node[now].r < l) return;
if(l <= node[now].l and node[now].r <= r) return (void)(ans += node[now].sum);
quary(l, r, ls, ans), quary(l, r, rs, ans);
return up(now);
}
}tree;
signed main(){
for(int i = 1; i <= 1000000; i ++){
for(int j = i; j <= 1000000; j += i){
d[j] ++;
}
}
scanf("%lld%lld", &n, &m);
for(int i = 1; i <= n; i ++) scanf("%lld", &a[i]);
tree.build(1, n, 1);
for(int i = 1, x, y, z; i <= m; i ++){
scanf("%lld%lld%lld", &x, &y, &z);
if(x&1) tree.chenge(y, z, 1);
else{
int ans = 0;
tree.quary(y, z, 1, ans);
printf("%lld\n", ans);
}
}
return 0;
}