因數的個數 線段樹維護
Let D(x) be the number of positive divisors of a positive integer x. For example, D(2)?=?2 (2 is divisible by 1 and 2), D(6)?=?4 (6 is divisible by 1, 2, 3 and 6).
You are given an array a of n integers. You have to process two types of queries:
- REPLACE l r — for every replace ai with D(ai);
- SUM l
Print the answer for each SUM query.
InputThe first line contains two integers n and m (1?≤?n,?m?≤?3·105) — the number of elements in the array and the number of queries to process, respectively.
The second line contains n integers a1, a2, ..., an (1?≤?ai?≤?106) — the elements of the array.
Then m lines follow, each containing 3 integers ti, li, ri denoting i-th query. If ti?=?1, then i-th query is REPLACE li ri, otherwise it‘s SUM li ri (1?≤?ti?≤?2, 1?≤?li?≤?ri?≤?n).
There is at least one SUM query.
OutputFor each SUM query print the answer to it.
Example Input7 6
6 4 1 10 3 2 4
2 1 7
2 4 5
1 3 5
2 4 4
1 5 7
2 1 7
30
13
4
22
題目分析 :題目說了一種操作,就是將一個數變成它的因數的個數,第二種操作是查詢一段區間的和,首先你觀察它的查詢和更改的操作次數有 3e5 次,查詢的話肯定是沒有問題的, logn 的復雜度,但是你更改呢?每個數都改,一定會超時,那麽要看下這些被改的數有什麽特征,一個很大的數,經過一次質因數操作,會變成一個相對很小的數,重復此過程,會變得越來越小,直到變成2,那麽我線段樹可以優化的地方是不就在這裏,設一個標記,就可以了
代碼示例 :
const ll maxn = 1e6+5; const ll maxn2 = 3e5+5; const double pi = acos(-1.0); const ll inf = 0x3f3f3f3f; #define lson k<<1 #define rson k<<1|1 ll cnt[maxn]; struct node { ll l, r; ll sum; ll pt; }t[maxn2<<2]; void init() { for(int i = 1; i <= 1000000; i++) cnt[i] = 2; cnt[1] = 1; for(int i = 2; i <= 1000000; i++){ for(int j = i+i; j <= 1000000; j += i) cnt[j]++; } } void pushup(int k){ t[k].sum = t[lson].sum + t[rson].sum; if (t[lson].pt && t[rson].pt) t[k].pt = 1; } void build(ll l, ll r, ll k){ t[k].l = l; t[k].r = r; t[k].pt = 0; if (l == r) { scanf("%lld", &t[k].sum); if (t[k].sum == cnt[t[k].sum]) t[k].pt = 1; return; } ll m = (l + r) >> 1; build(l, m, lson); build(m+1, r, rson); pushup(k); } ll query(ll l, ll r, ll k){ ll s = 0; if (l <= t[k].l && t[k].r <= r){ s += t[k].sum; return s; } ll m = (t[k].l + t[k].r) >> 1; if (l <= m) s += query(l, r, lson); if (r > m) s += query(l, r, rson); return s; } void update(ll l, ll r, ll k){ if (t[k].pt) return; if (t[k].l == t[k].r) { t[k].sum = cnt[t[k].sum]; if (t[k].sum == cnt[t[k].sum]) t[k].pt = 1; //printf("***** %lld\n", cnt[x]); return; } ll m = (t[k].l + t[k].r) >> 1; if (l <= m) update(l, r, lson); if (r > m) update(l, r, rson); pushup(k); } int main() { //freopen("in.txt", "r", stdin); //freopen("out.txt", "w", stdout); ll n, m; ll pt, l, r; init(); //for(ll i = 1; i <= 100; i++) printf("%lld %lld\n", i, cnt[i]); cin >> n >> m; build(1, n, 1); //printf("%lld\n", query(1, 7, 1)); for(ll i = 1; i <= m; i++){ scanf("%lld%lld%lld", &pt, &l, &r); if (pt == 1) { update(l, r, 1); } else { printf("%lld\n", query(l, r, 1)); } } return 0; }
因數的個數 線段樹維護