根号分治
根号分治
根号算法——不只是分块
适用类型:长度为\(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\n",f[x][y]);
else{
int az = 0,j;
for(az,j = y;j <= n;j += x)
az += a[j];
printf("%d\n",az);
}
}
else{
for(int j = 1;j <= p;j++)
f[j][x % j] += y-a[x];
a[x] = y;
}
}
}