链接:https://ac.nowcoder.com/acm/contest/392/F
来源:牛客网

时间限制:C/C++ 2秒,其他语言4秒
空间限制:C/C++ 32768K,其他语言65536K
64bit IO Format: %lld
题目描述
因为上次在月月面前丢人了,所以华华决定开始学信息学。十分钟后,他就开始学树状数组了。这是一道树状数组的入门题:
给定一个长度为N的序列A,所有元素初值为0。接下来有M次操作或询问:
操作:输入格式:1 D K,将A_DA
D

加上K。
询问:输入格式:2 L R,询问区间和,即\sum_{i=L}^{R}A_i∑
i=L
R

A
i


华华很快就学会了树状数组并通过了这道题。月月也很喜欢树状数组,于是给华华出了一道进阶题:
给定一个长度为N的序列A,所有元素初值为0。接下来有M次操作或询问:
操作:输入格式:1 D K,对于所有满足1\le i\le N1≤i≤N且i\equiv0(\mod D)i≡0(modD)的i,将A_iA
i

加上K。
询问:输入格式:2 L R,询问区间和,即\sum_{i=L}^{R}A_i∑
i=L
R

A
i


华华是个newbie,怎么可能会这样的题?不过你应该会吧。
输入描述:
第一行两个正整数N、M表示序列的长度和操作询问的总次数。
接下来M行每行三个正整数,表示一个操作或询问。
输出描述:
对于每个询问,输出一个非负整数表示答案。
示例1
输入
复制
10 6
1 1 1
2 4 6
1 3 2
2 5 7
1 6 10
2 1 10
输出
复制
3
5
26
备注:
1\le N,M\le10^51≤N,M≤10
5
,1\le D\le N1≤D≤N,1\le L\le R\le N1≤L≤R≤N,1\le K \le 10^81≤K≤10
8

思路:

这里我用 laze[i] 代表 i的倍数被加多少值

询问的时候暴力扫1~sqrtn 的laze,同时用数论分块可以知道 区间中i的倍数有多少个,计算贡献即可。

推荐博客:https://www.cnblogs.com/zjl192628928/p/10544105.html

细节见代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <queue>
#include <stack>
#include <map>
#include <set>
#include <vector>
#include <iomanip>
#define ALL(x) (x).begin(), (x).end()
#define sz(a) int(a.size())
#define all(a) a.begin(), a.end()
#define rep(i,x,n) for(int i=x;i<n;i++)
#define repd(i,x,n) for(int i=x;i<=n;i++)
#define pii pair<int,int>
#define pll pair<long long ,long long>
#define gbtb ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
#define MS0(X) memset((X), 0, sizeof((X)))
#define MSC0(X) memset((X), '\0', sizeof((X)))
#define pb push_back
#define mp make_pair
#define fi first
#define se second
#define eps 1e-6
#define gg(x) getInt(&x)
#define chu(x) cout<<"["<<#x<<" "<<(x)<<"]"<<endl
using namespace std;
typedef long long ll;
ll gcd(ll a, ll b) {return b ? gcd(b, a % b) : a;}
ll lcm(ll a, ll b) {return a / gcd(a, b) * b;}
ll powmod(ll a, ll b, ll MOD) {ll ans = 1; while (b) {if (b % 2)ans = ans * a % MOD; a = a * a % MOD; b /= 2;} return ans;}
inline void getInt(int* p);
const int maxn = 100010;
const int inf = 0x3f3f3f3f;
/*** TEMPLATE CODE * * STARTS HERE ***/
ll tree[maxn];
int n;
int lowbit(int x)
{
    return x & (-1 * x);
}
void add(int x, ll val)
{
    while (x <= n)
    {
        tree[x] += val;
        x += lowbit(x);
    }
}
ll ask(int x)
{
    ll res = 0ll;
    while (x)
    {
        res += tree[x];
        x -= lowbit(x);
    }
    return res;
}
ll laze[maxn];
// ll n;
int main()
{
    //freopen("D:\\common_text\\code_stream\\in.txt","r",stdin);
    //freopen("D:\\common_text\\code_stream\\out.txt","w",stdout);
    int m;
    scanf("%d", &n);
    scanf("%d", &m);
    int blocks=(int)(sqrt(n)+0.5);
    while(m--)
    {
        int op,l,r;
        scanf("%d %d %d",&op,&l,&r);
        if(op==1)
        {
            if(l>=blocks)
            {
                for(int i=l;i<=n;i+=l)
                {
                    add(i,1ll*r);
                }
            }else
            {
                laze[l]+=r;
            }
        }else
        {
            ll ans=ask(r)-ask(l-1);
            repd(i,1,blocks)
            {
                ans+=laze[i]*(r/i-(l-1)/i);
            }
            printf("%lld\n",ans );
        }
    }

    return 0;
}

inline void getInt(int* p) {
    char ch;
    do {
        ch = getchar();
    } while (ch == ' ' || ch == '\n');
    if (ch == '-') {
        *p = -(getchar() - '0');
        while ((ch = getchar()) >= '0' && ch <= '9') {
            *p = *p * 10 - ch + '0';
        }
    }
    else {
        *p = ch - '0';
        while ((ch = getchar()) >= '0' && ch <= '9') {
            *p = *p * 10 + ch - '0';
        }
    }
}