分塊是一種思想
它用於存在區間問題,並且結合律不是簡單相加的時候
線段樹和樹狀陣列此時不可用,這個時候,我們就要使用分塊
分塊思想是這樣的
設陣列長度是n,共有q塊,把陣列存下來,分成o(\(\frac\))段,每段記憶體乙個tag表示區間標記,當區間修改的時候,對於整塊,直接增加標記即可。
很類似線段樹的"標記永久化",思想都是一樣的,不過實現方法有很大差別。
而對於不滿一塊的情況下,直接暴力運算即可。
可以快速算出乙個操作對單獨的數的影響。
塊與塊一般情況下,n,m \(\leqslant\) 200000
當操作簡單或者資料水時,可以到500000
當塊長為o(\(\frac\))的時候,對於查詢,直接o(1)查詢陣列即可,注意加上tag。
對於區間修改,在塊內的修改,顯然最多把n個數全都改了,時間複雜度o(q)
在單塊的暴力修改,最多修改兩個塊長-2,時間複雜度2*n/q-2=\(\frac\)
∴時間複雜度為o(n/q+q);由均值不等式知,當q=\(\sqrt\)時,單次時間複雜度取最小值o(\(\sqrt\)).
附加:對於基礎區間查詢
區間查詢:類似區間加法,暴力統計左右不完整塊的答案,然後統計完整塊。時間複雜度:o(\(\sqrt\)).
為了方便,我們都預設下文的分塊大小為\(\sqrt\)。
例1:分塊1
#includeusing namespace std;
typedef long long ll;
int n,len;
int v[50005],b[50005],tag[50005];
void add(int l,int r,int d)
for(int i=b[l]+1;i<=b[r]-1;i++)tag[i]+=d;
}int main()
while(ch>='0'&&ch<='9')
return x*f;
}int n,len,b[120005],m;
ll v[120005],tag[120005],sum[120005];
void add(int l,int r,ll d)
if(b[l]!=b[r])
for(int i=(b[r]-1)*len+1;i<=r;i++)
v[i]+=d,sum[b[r]]+=d;
for(int i=b[l]+1;i<=b[r]-1;i++)tag[i]+=d;
}ll ask(int l,int r)
int main()
for(int i=1;i<=m;++i)
if(c==2)printf("%lld\n",ask(l,r));
}return 0;
}
分塊 學習筆記
當我們對於乙個很大陣列 1e5 進行區間修改和區間查詢時,我們會想到線段樹的 nlog n 的優秀效率。分塊 優雅的暴力!我們將區間分成每個大小為 s 的小塊,這樣我們的複雜度就會從 n 降到 frac n s 的效率。我們先將陣列分成長度為 s 小塊,用原下標除以 s 向上取整,就是他分塊後的小塊...
分塊學習筆記
在我不知道分塊以前,我一直以為分塊是乙個非常牛逼的東西。在我多次學習並且處於懵逼狀態的時候,我一直以為這輩子我不會分塊了。直到一天我學會了他。ps 乙個小建議,學習新知識要在上午哦 下面我就把剛剛學會的分塊做了一下總結。主要思想 分塊是乙個很暴力的演算法,跟普通的列舉暴力差不了多少。對於乙個長度為n...
分塊 學習筆記
前言 內容參考自感謝。分塊,是一種優雅的暴力,它通過對數列分段,完成對數列一些區間操作和區間查詢的操作,是一種根號演算法。本文屬於分塊入門筆記,旨在零基礎的同學學會分塊。1 建塊 在建塊伊始,我們需要完成一下幾個任務 1.確定塊的大小 2.確定塊的數量 3.標記每個塊的左右邊界 4.標記每個元素所屬...