码迷,mamicode.com
首页 > 其他好文 > 详细

因数的个数 线段树维护

时间:2018-02-03 20:52:17      阅读:148      评论:0      收藏:0      [点我收藏+]

标签:区间   highlight   ble   log   printf   can   alc   复杂   tin   

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:

  1. REPLACE l r — for every 技术分享图片 replace ai with D(ai);
  2. SUM l r — calculate 技术分享图片.

Print the answer for each SUM query.

Input

The 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.

Output

For each SUM query print the answer to it.

Example
Input
7 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
Output
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;
}

 

因数的个数 线段树维护

标签:区间   highlight   ble   log   printf   can   alc   复杂   tin   

原文地址:https://www.cnblogs.com/ccut-ry/p/8410489.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!