根號分治
阿新 • • 發佈:2020-08-12
根號分治
根號演算法——不只是分塊
適用型別:長度為\(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; } } }