CF920F SUM and REPLACE
阿新 • • 發佈:2020-09-16
題意:
給定 \(n\) 個數的陣列 \(a\),\(m\) 次操作。操作有兩種:
- 將 \(i\in[l,r]\) 中的所有 \(a_i\) 替換為 \(d(a_i)\)。\(d(x)\) 表示 \(x\) 的正約數的個數。
- 求 \(\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; }