1. 程式人生 > 實用技巧 >CF920F SUM and REPLACE

CF920F SUM and REPLACE

題意:

給定 \(n\) 個數的陣列 \(a\)\(m\) 次操作。操作有兩種:

  1. \(i\in[l,r]\) 中的所有 \(a_i\) 替換為 \(d(a_i)\)\(d(x)\) 表示 \(x\) 的正約數的個數。
  2. \(\displaystyle\sum_{i=l}^r a_i\)

觀察:

我們假如一直對\(1000000\)進行操作\(1\),我們可以發現過程是這樣的:

\(1000000\)\(49\)\(3\)\(2\)

然後就一直會是\(2\)

無一例外。每個數都會經過多次操作要麼會變成\(1\)要麼會變成\(2\)

而且在以後對這個數進行操作的時候是不會再發生改變的。

多次操作的次數最多為\(6\)次。

思路:

\(d\)是可以預處理出來的。

線性篩太麻煩了?有這樣一種預處理方式:

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 qwq

時間複雜度\(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;

namespace fast_read{
	template<typename temp>
	temp read(temp &x){
		x = 0;temp f = 1;char ch;
		while(!isdigit(ch = getchar())) (ch == '-') and (f = -1);
		for(x = ch^48; isdigit(ch = getchar()); x = (x<<1)+(x<<3)+(ch^48));
		return x *= f;
	}
	template <typename temp, typename ...Args>
	void read(temp& a, Args& ...args){read(a), read(args...);}
	inline int read(){
		int x = 0, f = 1;char ch;
		while(!isdigit(ch = getchar())) (ch == '-') and (f = -1);
		for(x = ch^48; isdigit(ch = getchar()); x = (x<<1)+(x<<3)+(ch^48));
		return x *= f;
	}
}using namespace fast_read;

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] ++;
		}
	}
	read(n, m);
	for(int i = 1; i <= n; i ++) read(a[i]);
	tree.build(1, n, 1);
	for(int i = 1, x, y, z; i <= m; i ++){
		read(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;
}