根号分治
根号算法——不只是分块
适用类型:长度为(n)的序列,(m)个询问,(n和)(m)通常同阶,显然的方法有(O(n^2))预处理,(O(1))回答,一种是不预处理,
(O(n))回答(m)个询问,根号分治可以做到(O((n+m)sqrt n))
luogu P3396 哈希冲突
从(k)开始,每隔(p)个数取一个数,求它们的和
for(i=k;i<=n;i+=p) ans += value[i];
令答案为(ans[p][k]),模数是(p),余数是(k),对第(i)个数,处理它对ans贡献
for(p = 1;p <= n;p++) ans[p][i % p] += val[i];
#include<cstdio>
#include<cmath>
using namespace std;
const int S = 150003,N = 403;
int a[S],f[N][N];//f[i][j]模数是i余数是j
int n,m,p,x,y; char e[2];
inline int read(){
int x=0; char c=std::getchar();
while(c<'0'||c>'9')c=std::getchar();
while(c>='0'&&c<='9'){x=(x<<3)+(x<<1)+(c^48);c=std::getchar();}
return x;}
int main(){
n = read(); m = read(); p = sqrt(n);//pow(n,0.33)更快
for(int i = 1;i <= n;i++){
a[i] = read();
for(int j = 1;j <= p;j++)
f[j][i % j] += a[i];
}
for(int i = 1;i <= m;i++){
scanf("%s",e);x = read(); y = read();
if(e[0] == 'A'){
if(x <= p) printf("%d
",f[x][y]);
else{
int az = 0,j;
for(az,j = y;j <= n;j += x)
az += a[j];
printf("%d
",az);
}
}
else{
for(int j = 1;j <= p;j++)
f[j][x % j] += y-a[x];
a[x] = y;
}
}
}