根号分治
前言
本题是一道讲解根号分治思想的论文题(然鹅我并没有找到论文),正
如论文中所说,根号算法——不仅是分块,根号分治利用的思想和分块像
似却又不同,某一篇洛谷日报中说过,分块算法实质上是一种是通过分成
多块后在每块上打标记以实现快速区间修改,区间查询的一种算法。根号
分治与其思路相似,将原本若一次性解决时间复杂度很高的问题分块去解
决来降低整体的时间复杂度。
例题
以本题举例子哈希冲突
本题作为论文的第一道题目,是一道很好的练习题,注意,本体给出的
(value[i]) 是 (i) 在序列中出现的次数,不要把题读错了(一开始我就读错了)
我们首先阅读题目,发现,无论是 (O(n^2)) 预处理, (O(1)) 查询,还是在
查询时直接(O(n^2))获取答案,都是 (O(n^2)) 的时间复杂度,我们考虑对
其进行优化,我们可以考虑将(p),也就是模数按根号分块处理
对于 (p<=sqrt{q}) 我们直接 (O(nsqrt{n})) 进行预处理,
for(int i=1;i<=n;i++){
v=read();
val[i]=v;
}
size=sqrt(n);
for(int i=1;i<=n;i++){
for(int p=1;p<=size;p++){
ans[p][i%p]+=val[i];
}
}
(ans[p][i]) 表示在 (%p) 后值为 (i)的数的个数
对 (p>sqrt{q}) 的情况,
我们直接暴力得出答案,暴力得到答案的时间复杂度为 (O(sqrt{n}))
int an=val[y];
for(int i=x+y;i<=n;i+=x){
an+=val[i];
}
cout<<an<<endl;
(an=val[y]) 是为了处理 (y%x=y) ((y<x)) 的情况,为什么说我们暴力跳
答案时间复杂度是 (O(sqrt{n})) 呢?我们当前的 (p>sqrt{n})) 因为统
计答案时每一次要跳(p)个数,所以有贡献的数一定小于 (frac{n} {p}) 也就是 (sqrt{n}) ,所以暴力得到答案的时间复杂度为 (O(sqrt{n}))
每一次修改,我们只需要修改 (p<=sqrt{n}) 的情况即可,时间复杂度也是 (O(sqrt{n}))
cin>>x>>y;
int l=y-val[x];
val[x]=y;
for(int p=1;p<=size;p++){
ans[p][x%p]+=l;
}
所以在本题,我们运用根号分治的想法,把时间复杂度由原本的(O(n^2))
优化到了 (O(nsqrt{n})) 从而解决本题。
莫名觉得根号分治挺像折半搜索
,推荐一道练习题CF444D DZY Loves Strings
还是很有难度的
代码
放一下全部代码吧
#include<iostream>
#include<string>
#include<string>
#include<cstdio>
#include<cmath>
#define int long long
using namespace std;
const int maxn=3e5+10;
inline int read(){
int ret=0;
int f=1;
char ch=getchar();
while(ch<'0'||ch>'9'){
if(ch=='-')
f=-f;
ch=getchar();
}
while(ch<='9'&&ch>='0'){
ret=ret*10+(ch^'0');
ch=getchar();
}
return ret*f;
}
int val[maxn];
int n,m;
int p;
int ans[2000][2000];
int size;
char a;
signed main(){
// freopen("a.in","r",stdin);
n=read();
m=read();
int v;
for(int i=1;i<=n;i++){
v=read();
val[i]=v;//????????
}
size=sqrt(n);//????
for(int i=1;i<=n;i++){
for(int p=1;p<=size;p++){
ans[p][i%p]+=val[i];
}
}
int x,y;
while(m--){
cin>>a;
if(a=='A'){
x=read();
y=read();
if(x<=size){
cout<<ans[x][y]<<endl;
}
else{
int an=val[y];
for(int i=x+y;i<=n;i+=x){
an+=val[i];
}
cout<<an<<endl;
}
}
if(a=='C'){
cin>>x>>y;
int l=y-val[x];
val[x]=y;
for(int p=1;p<=size;p++){
ans[p][x%p]+=l;
}
}
}
return 0;
}
到这里本题解就结束了
完结撒花!!