题意:
一个长度为 的数组,初始为空,支持两种操作。操作 , 表示将 增加 。操作 , ,表示统计所有下标模 为 的数的和,一共有 次操作。
思路:
昨晚最后有半个小时写这题,但是还是没有啥思路,完全没有往分块上去想…分块技能树有点缺乏啊!最后 ,感觉搞不定了,乱打一发线段树成功 …自闭了…
所以正解就是分块,当然分块的复杂度为 。我们来考虑下此题如何进行分块,显然要对于模数进行分类。 ,我们对于模数大于 的数,直接暴力求,复杂度为 。对于模数小于 的数,我们预先统计答案直接求得。
那么对于模数小于 的数,如何预先处理答案呢?对于 ,我们暴力所有模数, 表示模 为 的数的 和。因此我们令 ,这样的复杂度也是 ,因此最终复杂度为 ,分块成功。
总结:
反思一下为什么没有想到分块,如果想到了分块,按理来说思路也没有那么难想。
这么看来的话,应该是思维体系里完全没有分块这个意识,数据结构的技能树里分块这里非常灰暗…看来还是非常有必要抽出一段时间来巩固所有的基础专题。继续加油!
代码:
#include <bits/stdc++.h>
#define __ ios::sync_with_stdio(0);cin.tie(0);cout.tie(0)
#define rep(i,a,b) for(int i = a; i <= b; i++)
#define LOG1(x1,x2) cout << x1 << ": " << x2 << endl;
#define LOG2(x1,x2,y1,y2) cout << x1 << ": " << x2 << " , " << y1 << ": " << y2 << endl;
#define LOG3(x1,x2,y1,y2,z1,z2) cout << x1 << ": " << x2 << " , " << y1 << ": " << y2 << " , " << z1 << ": " << z2 << endl;
typedef long long ll;
typedef double db;
const int N = 5*1e5+100;
const db EPS = 1e-9;
using namespace std;
ll a[N],b[715][715];
int main()
{
int _; scanf("%d",&_);
while(_--){
int op; scanf("%d",&op);
if(op == 1){
int x,y; scanf("%d%d",&x,&y);
a[x] += y;
rep(i,1,710) b[i][x%i] += (ll)y;
}
else{
int x,y; scanf("%d%d",&x,&y);
if(x <= 710) printf("%lld\n",b[x][y]);
else{
ll tp = 0;
for(int i = y; i <= (int)5*1e5; i += x) tp += a[i];
printf("%lld\n",tp);
}
}
}
return 0;
}