根號分治
前言
本題是一道講解根號分治思想的論文題(然鵝我並沒有找到論文),正
如論文中所說,根號演算法——不僅是分塊,根號分治利用的思想和分塊像
似卻又不同,某一篇洛穀日報中說過,分塊演算法實質上是一種是通過分成
多塊後在每塊上打標記以實現快速區間修改,區間查詢的一種演算法。根號
分治與其思路相似,將原本若一次性解決時間複雜度很高的問題分塊去解
決來降低整體的時間複雜度。
例題
以本題舉例子雜湊衝突
本題作為論文的第一道題目,是一道很好的練習題,注意,本體給出的
\(value[i]\) 是 \(i\) 在序列中出現的次數,不要把題讀錯了(一開始我就讀錯了)
我們首先閱讀題目,發現,無論是 \(O(n^2)\) 預處理, \(O(1)\) 查詢,還是在
查詢時直接\(O(n^2)\)獲取答案,都是 \(O(n^2)\) 的時間複雜度,我們考慮對
其進行優化,我們可以考慮將\(p\),也就是模數按根號分塊處理
對於 \(p<=\sqrt{q}\) 我們直接 \(O(n\sqrt{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(n\sqrt{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;
}
到這裡本題解就結束了
完結撒花!!