根号分治

根号分治

根号算法——不只是分块

适用类型:长度为\(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;
		}
	}
}
posted @ 2020-08-12 15:56  INFP  阅读(243)  评论(0编辑  收藏  举报