2024.3.14 樹鏈剖分

O_JF?發表於2024-03-15
//參考 https://oi-wiki.org/graph/hld/#%E4%BE%8B%E9%A2%98
//例題 //https://loj.ac/p/10138 https://www.luogu.com.cn/problem/P3379
vector<int>G[N];
int son[N];
int siz[N];
int fa[N];
int dep[N];
void dfs1(int o) {
  	son[o] = -1;
  	siz[u] = 1;
  	for (int v:G[u]){
      	if(dep[v]) continue;
      	fa[v]=u;
      	dep[v]=dep[u]+1;
      	dfs1(v);
      	siz[u]+=siz[v];
      	if(!son[u]||siz[v]>size[son[u]]) son[u]=v;
  }
}
void dfs2(int u, int f) {
  	top[u] = f;
  	dfn[u] = ++cnt;
  	rnk[cnt] = u;
  	if (!son[u]) return;
  	dfs2(son[u], f);
  	for (int v : G[u]) {
      	if(v==son[u]||v==f) continue;
      	dfs2(v,v);
  	}
}
// 因為重鏈是連續的dfn序列,所以根據這個特性,將樹變為一個序列配合線段樹,可以查詢點、邊的(最大值,和)
// 原理:位於輕鏈,暴力慢慢移動到重鏈;位於重鏈,線段樹最佳化移動到重鏈頭,直到兩者位於同一條重鏈,再用線段樹線段樹計算距離
// st 是線段樹結構體
int querymax(int x, int y) {
  int ret = -inf, fx = top[x], fy = top[y];
  while (fx != fy) {
    if (dep[fx] >= dep[fy])
      ret = max(ret, st.query1(1, 1, n, dfn[fx], dfn[x])), x = fa[fx];
    else
      ret = max(ret, st.query1(1, 1, n, dfn[fy], dfn[y])), y = fa[fy];
    fx = top[x];
    fy = top[y];
  }
  if (dfn[x] < dfn[y])
    ret = max(ret, st.query1(1, 1, n, dfn[x], dfn[y]));
  else
    ret = max(ret, st.query1(1, 1, n, dfn[y], dfn[x]));
  return ret;
}

過知識點

相關文章