zoukankan      html  css  js  c++  java
  • 因数的个数 线段树维护

    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
    ", 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
    ", i, cnt[i]);
        cin >> n >> m;
        build(1, n, 1);
        //printf("%lld
    ", 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
    ", query(l, r, 1));
            }    
        }
        return 0;
    }
    
    东北日出西边雨 道是无情却有情
  • 相关阅读:
    命令行程序测试自动化
    微软的PivotViewer控件编程续
    使用Autofac实现依赖注射及Ioc
    微软的PivotViewer控件编程
    求最大公约数(GCD)的两种算法
    编译原理学习笔记一(待续)
    如果你想创业,又担心腾讯照抄你的好点子的话,可以看看下面的文章。
    从测试的角度来重新反思我们自己的程序以及我们的程序员之路——“通过追本溯源来进行前瞻性思考”
    Ubuntu11.10安装飞信
    2012.3.27《JAVA程序设计教程》
  • 原文地址:https://www.cnblogs.com/ccut-ry/p/8410489.html
Copyright © 2011-2022 走看看