题意
- 对于长为n的全0序列,完成m次如下两种操作
- 输入x y,将所有1-base下标为x的倍数的元素加上y
- 输入x y,输出x到y区间和
思路
- 对于操作1,如果暴力做,每次的复杂度会是
&preview=true)
- 分析x
- 如果x很大,那么x的倍数就不会很多,暴力的复杂度是可以接受的
- 如果x很小,通过数学可以快速得到需要增加的元素的个数,开一个桶,记录每个x被加的y的总和,最后统一计算贡献(这个方法在x大的时候设计开不下数组的问题)
- x的分界定多大
- 采用上面的方法后,修改的复杂度变为
,查询的复杂度变为
,由均值不等式得分界定在
即可
代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
int c[202020],flg[1010];
int n,m;
int lowbit(int x){ return x&(-x); }
void add (int x,int val){
while(x<=n){
c[x]+=val;
x+=lowbit(x);
}
}
int cal(int x){
int sum=0;
while(x>0){
sum+=c[x];
x-=lowbit(x);
}
return sum;
}
signed main(){
cin >> n >> m ;
while(lowbit(n)!=n) n+=lowbit(n);
for(int i=1;i<=m;i++){
int op,x,y;
cin >> op >> x >> y;
if(op==1){
if(x*x<=n){
flg[x]+=y;
}else{
for(int j=x;j<=n;j+=x){
add(j,y);
}
}
}else{
int ans=cal(y)-cal(x-1);
for(int j=1;j*j<=n;j++){
ans+=((y/j)-((x-1)/j))*flg[j];
}
cout << ans << endl;
}
}
}