當我們對於乙個很大陣列 \((1e5)\) 進行區間修改和區間查詢時,我們會想到線段樹的 \(nlog_n\) 的優秀效率。
分塊——優雅的暴力!!!
我們將區間分成每個大小為 \(s\) 的小塊,這樣我們的複雜度就會從 \(n\) 降到 \(\frac n s\) 的效率。
我們先將陣列分成長度為 \(s\) 小塊,用原下標除以 \(s\) 向上取整,就是他分塊後的小塊標號。
void init()
}
若我們要將 \(l\) 到 \(r\) 的區間內都加上權值 \(w\)。
若這個區間在乙個小塊裡面
直接 \(s\) 的效率乙個乙個修改即可。
若這個區間橫跨了多個小塊
如下圖
我們先用 \(s\) 效率將左右兩端無法組成乙個塊的單點都加上。
然後對於中間的塊,乙個乙個塊都打上標記,跟線段樹上的標記差不多,最後區間查詢時加上即可。
void modify(int l, int r, int w)
}else
}}
跟區間修改的思想類似
若這個區間在乙個小塊裡面
將這個塊裡標記值加上,在加上單點的值即可。
若這個區間橫跨了多個小塊
將無法組成左右無法組成乙個小塊的部分用上面的思路加和。
剩下的一塊一塊直接加上 \(sum[i]\) 即可。
inline int query(int l, int r)
}else
} return ans;
}
自我感覺比線段樹好寫,而且在某些題上會比線段樹跑得快。
例如這個板子題
打一波廣告
#include #include #include #include #include using namespace std;
const int maxn = 1e5 + 50, inf = 0x3f3f3f3f;
inline int read()
int n, m, s;
int a[maxn];
int bel[maxn], size[maxn], sum[maxn], l[maxn], r[maxn];
int tag[maxn];
void init()
}void modify(int l, int r, int w)
}else }}
inline int query(int l, int r)
}else
} return ans;
}int main()
init();
while (m --) else
} return 0;
}
分塊學習筆記
在我不知道分塊以前,我一直以為分塊是乙個非常牛逼的東西。在我多次學習並且處於懵逼狀態的時候,我一直以為這輩子我不會分塊了。直到一天我學會了他。ps 乙個小建議,學習新知識要在上午哦 下面我就把剛剛學會的分塊做了一下總結。主要思想 分塊是乙個很暴力的演算法,跟普通的列舉暴力差不了多少。對於乙個長度為n...
分塊 學習筆記
前言 內容參考自感謝。分塊,是一種優雅的暴力,它通過對數列分段,完成對數列一些區間操作和區間查詢的操作,是一種根號演算法。本文屬於分塊入門筆記,旨在零基礎的同學學會分塊。1 建塊 在建塊伊始,我們需要完成一下幾個任務 1.確定塊的大小 2.確定塊的數量 3.標記每個塊的左右邊界 4.標記每個元素所屬...
分塊學習筆記
題面傳送門 演算法簡介 分塊主要是乙個修改,維護區間的東西,它可以做到一邊修改一邊查詢,區間修改 o sqrt n 區間查詢 o sqrt n 單點修改 o 1 單點查詢 o 1 演算法實現 初始化 首先要把基本陣列 以下簡稱 a 陣列,長度為 n 分成 m 塊。一般是分成 sqrt n 塊,當然也...