AcWing算法提高课 Level-3 第四章 高级数据结构
生活随笔
收集整理的這篇文章主要介紹了
AcWing算法提高课 Level-3 第四章 高级数据结构
小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.
并查集
1250. 格子游戲
- 并查集解決的是連通性(無向圖聯(lián)通分量)和傳遞性(家譜關(guān)系)問題,并且可以動態(tài)的維護(hù)。拋開格子不看,任意一個圖中,增加一條邊形成環(huán)當(dāng)且僅當(dāng)這條邊連接的兩點已經(jīng)聯(lián)通,于是可以將點分為若干個集合,每個集合對應(yīng)圖中的一個連通塊。
- 并查集(典型并查集判斷是否存在環(huán)的問題)
- 并查集中一般用一維的坐標(biāo)會方便一些,所以這個題要把二維坐標(biāo)轉(zhuǎn)化成一維坐標(biāo),有個很常用的方式,(x,y) -> x*n+y,前提是x和y都從0開始
- 將每個坐標(biāo)看成一個點值,為了方便計算,將所有的坐標(biāo)橫縱坐標(biāo)都減1,第一個位置即(1,1)看成是0,(1,2)看成是1,依次類推,將所有的坐標(biāo)橫縱坐標(biāo)都減1后,假設(shè)當(dāng)前點是(x,y),則該點的映射值是a = (x * n + y),若向下畫,則b = [(x + 1) * n + y],若向右畫,則b = [x * n + y - 1]
- 并查集操作復(fù)雜度接近O(1),本來應(yīng)該這題是O(n+m),但由于實現(xiàn)時只用了路徑壓縮,沒有用什么什么合并,所以本質(zhì)這道題復(fù)雜度是mlogn的,但這個logn非常小,因為并查集常數(shù)很小,
樹狀數(shù)組
- 樹狀數(shù)組相較于數(shù)組和前綴和數(shù)組的作用
- 采取的是二進(jìn)制思想,例如求1~x的和,就可以用下圖的方案在log(x)中算出;即可以在log(n)時間內(nèi)算出前n項的前綴和
- 那如何求每個區(qū)間的和呢?先看看區(qū)間的性質(zhì),第一個區(qū)間包含2i12^{i_1}2i1?個數(shù),第二個區(qū)間包含2i22^{i_2}2i2?個數(shù),以此類推,然后發(fā)現(xiàn)2i12^{i_1}2i1?是x的二進(jìn)制表示的最后一位1,2i22^{i_2}2i2?是x - 2i12^{i_1}2i1?的最后一位1。因此,在這樣的(L, R]區(qū)間中,這個區(qū)間長度一定是R的二進(jìn)制表示的最后一位1所對的次冪。(lowbit(x)是O(1)的),那么這個區(qū)間形式就可以改寫為[R-lowbit( R)+1,R],那么就可以用數(shù)組,C[R]來表示這個區(qū)間的總和了,這樣的區(qū)間最多有n個。
- C[x] = a[x - lowbit( x) + 1, x],對于每個x而言,1~x的所有數(shù)的和,最多可以拆成log(x)個C[x]的和,所以是log(n)
- 這樣就挖掘出了所有不同C之間的關(guān)系
241. 樓蘭圖騰
#include <iostream> #include <cstring>using namespace std;typedef long long ll;const int N = 2e5 + 10;int n; int a[N], tr[N]; int Greater[N], lower[N];int lowbit(int x) {return x & (-x); }void add(int x, int c) {for (int i = x; i <= n; i += lowbit(i)) tr[i] += c; }int sum(int x) {int res = 0;for (int i = x; i; i -= lowbit(i)) res += tr[i];return res; }int main() {scanf("%d", &n);for (int i = 1; i <= n; i ++ ) scanf("%d", &a[i]);// 從左到右for (int i = 1; i <= n; i ++ ){int y = a[i];Greater[i] = sum(n) - sum(y); // [y + 1, n] // y + 1 ~ n之間已出現(xiàn)的數(shù)的個數(shù)lower[i] = sum(y - 1); // [1, y - 1] // 1 ~ y - 1之間已出現(xiàn)的數(shù)的個數(shù)add(y, 1); // 記錄y這個數(shù)已經(jīng)出現(xiàn)了}memset(tr, 0, sizeof tr); // 清空,重新建樹,之間是從左向右遍歷數(shù)組建樹,后面要從右向左了ll res1 = 0, res2 = 0;for (int i = n; i; i -- ){int y = a[i];res1 += Greater[i] * (ll)(sum(n) - sum(y));res2 += lower[i] * (ll)(sum(y - 1));add(y, 1);}printf("%lld %lld", res1, res2);return 0; }線段樹
// 簡單線段樹的操作 ://傳入節(jié)點編號,用子節(jié)點信息來算父節(jié)點信息 push up(int u)//將一段區(qū)間初始化為一顆線段樹 build()//修改操作,修改某一個點或者某一個區(qū)間(懶標(biāo)記) modify()//查詢某一段區(qū)間的信息 query()- 定義 :線段樹是一顆滿二叉樹,以一顆長度為10的序列為例 :
- N個葉結(jié)點的滿二叉樹有N + N/2 + N/4 + … = 2N-1個結(jié)點,因為在上述存儲方式下,最后還有一層產(chǎn)生了空余,最后一層最壞情況下是上一層的兩倍,也就是還有2N個,所以保存線段樹的數(shù)組長度要不小于4N
- 線段樹的查詢操作,例如查詢【5, 9】,有8個區(qū)間要查 。且可以發(fā)現(xiàn)為log(n),不過最多有4logn,而樹狀數(shù)組只有1logn,所以線段樹復(fù)雜度更大
- 線段樹的結(jié)構(gòu) :
- 線段樹的建樹 :
- push_up操作 :
- 查詢操作 :
- 修改操作
1275. 最大數(shù)
- 這道題的兩個操作可以被轉(zhuǎn)化成上述兩個操作,而這兩個操作就是線段樹的經(jīng)典操作,動態(tài)修改某個位置上的數(shù),動態(tài)查詢某個區(qū)間內(nèi)的最大值
- 不過,這個問題比較特殊,每個位置只會被修改一次,因此這題可以用RMQ算法做,可以看作靜態(tài)問題,不過局限性比較大,只能處理靜態(tài)數(shù)據(jù)。但其實不是如此,這題由于每次修改的時候依賴上一次查詢的,是動態(tài)的問題,不能把它全部讀進(jìn)來然后預(yù)處理去做的,所以不能用RMQ
- 注意!!凡是只要修改某一個點,單點,的,都不需要用到懶標(biāo)記,本身都可以做到Logn的復(fù)雜度;凡是涉及到區(qū)間的,修改整一個區(qū)間的,這樣的操作,一般都需要加上懶標(biāo)記,否則復(fù)雜度會退化
- pushup由兒子算父節(jié)點的信息,pushdown是父節(jié)點的修改更新到兒子上面
可持久化數(shù)據(jù)結(jié)構(gòu)
- 可持久化的前提 :這個數(shù)據(jù)結(jié)構(gòu)本身的拓?fù)浣Y(jié)構(gòu)在操作過程中保持不變。
- 可持久化數(shù)據(jù)結(jié)構(gòu) :1.trie的可持久化。2.線段樹的可持久化-主席樹。比如線段樹,只會變線段樹里面的信息,線段樹本身是不會發(fā)生變化的。樹狀數(shù)組每個結(jié)點的兒子也是固定不變的,變的只是里面存的信息。堆也是,結(jié)構(gòu)不會發(fā)生變化,完全二叉樹;而有些數(shù)據(jù)結(jié)構(gòu)會發(fā)生拓?fù)湫虻淖兓?#xff0c;比如平衡樹,左旋和右旋,操作后結(jié)點之間的拓?fù)湫驎l(fā)生變化。
- 可持久化解決的問題是什么 :可以存下來數(shù)據(jù)結(jié)構(gòu)的所有歷史版本
- 核心思想 :只會記錄當(dāng)前版本和前一個版本不一樣的地方。比如線段樹,每次修改,如果n個結(jié)點,操作涉及最多4logn個結(jié)點,每次操作最多改變的節(jié)點數(shù)只有o(logn)個。即,最多只會記錄mlogn個結(jié)點
- 可持久化trie :
- 凡是有變化的點就裂開成一個新的點,比如根結(jié)點就每次必然有變化
256. 最大異或和
- 原始數(shù)據(jù)最多有3e5,再加上3e5個操作,因此整個序列長度最大是6e5
- 2^24正好大于10 ^7,所以trie長度最多為24,再加上根結(jié)點,所以每次最多建立25個新結(jié)點
平衡樹Treap
253. 普通平衡樹
AC自動機(jī)
1282. 搜索關(guān)鍵詞
總結(jié)
以上是生活随笔為你收集整理的AcWing算法提高课 Level-3 第四章 高级数据结构的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 黑马程序员pink老师前端入门教程,零基
- 下一篇: 树状数组 求 逆序对