樹上演算法01-倍增LCA/Trie
阿新 • • 發佈:2022-03-30
樹-相關演算法
定義
-
任意兩個節點之間只有唯一一條路徑的無向圖
-
\(n\)個節點,\(n - 1\)條邊
建樹方法
鏈式前向星(提供邊的資訊)
//儲存 struct edge{ int to; int pre; }e[ll]; //加邊 void add(int x, int y){ e[++cnt].to = y; e[cnt].pre = last[x]; last[x] = cnt; } //遍歷 for(int i = last[cur];i;i = e[i].pre){ if(e[i].to != fa)dfs(e[i].to,cur); }
二叉/三叉連結串列
大家都會寫
LCA演算法
- 對於兩個節點,首先其深度不同
- 移動一個節點直到二者深度相同
- 深度相同以後再向上尋找祖先
- 從距離最遠的祖先開始跳,如果找到的祖先不相同就跳
- 最後停在LCA下面一層
倍增法
查詢
int lca(int x,int y){ if(depth[x] > depth[y]){ int tmp; tmp = x; x = y; y = tmp; }//y is always deeper int two = 0; int d = depth[y] - depth[x]; while(d){ if(d%2)y = f[y][two]; ++two; d /= 2; } if(x == y) return y; //一起跳 for(int i = 20; i >= 0; --i){ if(f[x][i] != f[y][i]){ x = f[x][i]; y = f[y][i]; } } return f[x][0]; }
是誰把多叉樹當二叉樹做啊
是我啊
那沒事了
DFS預處理
- DFS預處理,求出每個節點的不同級別祖先
- 記錄深度
void dfs(int cur,int fa){ depth[cur] = depth[fa] + 1; f[cur][0] = fa; for(int i = 1; (1<<i) < depth[cur]; ++i){ f[cur][i] = f[f[cur][i-1]][i - 1]; } for(int i = last[cur];i;i = e[i].pre){ if(e[i].to != fa)dfs(e[i].to,cur); } }
差分陣列
給出一個數組{\(a_i\)}
差分陣列為{\(a_i - a_{i -1}\) }\((a_0 = 0)\)
便於對某一段區間進行統一的+n的操作,僅需改變區間頭尾兩個數字
查詢原陣列中某個數即求一段字首和
差分樹
\(def:fa = fa - ls - rs\)
支援對u到v路徑上的所有點權值修改後,只需修改u、v、pla、pla ‘ s father四個點的值即可
所有修改結束以後將樹還原
進行後續查詢操作
樹上預處理-邊
dfs將每條邊上的值放到下面的節點裡
異或題:每個節點儲存到根的異或值
樹上最短路
詢問路徑長度
差分樹:\(fa - (ls +rs)\)
DFS預處理:每個點記錄到根的長度
\(Length_{uv} = l_u + l_v - 2l_{LCA}\)
包含點集最小子樹的帶權路徑和
三個點其實與兩個點的沒有太大差別,實在是弱搞得好複雜
對於任意三個點
可以用這個方法:\((1\rightarrow2+1\rightarrow3+2\rightarrow3)/2\)
然後來看四個點
如果把所有點兩兩跑一遍
\(length = a + b+a+c+a+d+b+c+b+d+c+d\)
\(length = 3(a+b+c+d)\)
再來看這棵樹
\(length = a+b+a+b+c+a+d+c+b+d+c+b+d\)
??不符合條件
需要用到虛樹相關知識(pks)
trie樹(儲存字串用於多模式串匹配)
儲存實現
int node[lll][30];//記錄節點兒子的編號
功能函式
- insert
void insert(string s){
int root = 0;
for(int i = s.length() - 1; i >= 0; --i){
int d = s[i] - 'a';
if(!node[root][d])node[root][d] = ++cnt;
root = node[root][d];
}
e[root] = true;
}
- find
bool find(string s){
int root = 0;
for(int i = 0; i < s.length(); ++i){
int d = s[i] - 'a';
if(!node[root][d])return false;
root = node[root][d];
}
if(e[root])return true;//結束位置
return false;
}