分塊學習筆記

2022-10-11 16:39:11 字數 1405 閱讀 1044

分塊是一種思想

它用於存在區間問題,並且結合律不是簡單相加的時候

線段樹和樹狀陣列此時不可用,這個時候,我們就要使用分塊

分塊思想是這樣的

設陣列長度是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.標記每個元素所屬...