最近公共祖先(LCT)

2022-05-19 20:26:23 字數 1480 閱讀 6819

\(lct\)在時間上不佔據優勢,碼量似乎還比樹剖,倍增,\(tarjan\)大一點

但是卻是一道\(lct\)的練手題

對於每乙個詢問,我們只需要把其中乙個點(我們設為a)先\(access\),這樣a到根節點的路徑就都在一棵\(splay\)裡面了

而且不難發現,有乙個很妙的性質:如果兩個點不在一條路徑上(即\(lca!=a||lca!=b\))那麼b點\(access\)以後,b第一次到a到\(root\)的\(splay\)的上的點即為\(lca\)

然後我們考慮在將另乙個點(我們設為b)與根的路徑打通,我們還是一樣一直\(splay\),對於最後一棵\(splay\)

\(lca\)即為b第一次到a和rt的那一棵\(splay\)的位置

那麼a,b本來在乙個\(splay\)上呢?

其實也是一樣的,我們在分類討論

1)若\(dep[a]>dep[b]\)那麼顯然不影響答案,答案就是b點

2)若\(dep[a]那麼我們在\(access(a)\)時候,a,b就已經不在一顆\(splay\)裡了,所以也不影響答案

**如下:

#includeusing namespace std;

#define il inline

#define re register

il int read()

while(c >= '0' && c <= '9') x = x * 10 + c - 48, c = getchar();

return x * f;

}#define get_fa(x) (ch[1][fa[x]] == x)

#define isroot(x) (ch[1][fa[x]] == x || ch[0][fa[x]] == x)

#define updown(x) swap(ch[1][x], ch[0][x]), tag[x] ^= 1

#define rep(i, s, t) for(re int i = s; i <= t; ++ i)

#define maxn 500005

int n, m, s, ch[2][maxn], fa[maxn], st[maxn], top, tag[maxn];

il void pushdown(int x)

}il void rotate(int x)

il void splay(int x)

}il void access(int x)

il void makeroot(int x)

il void link(int a, int b)

il int query(int a, int b)

int main()

makeroot(s);

while(m --)

return 0;

}

最近公共祖先 python 最近公共祖先

lca演算法樸素演算法 也就是我們所說的暴力演算法,大致的思路是從樹根開始,往下迭代,如果當前結點比兩個結點都小,那麼說明要從樹的右子樹中找 相反則從左子樹中查詢 直到找到乙個結點在當前結點的左邊,乙個在右邊,說明當前結點為最近公共祖先,如果乙個結點是另外乙個結點的祖先,那麼返回前面結點的父親結點即...

最近公共祖先 LCA 最近公共祖先

直接暴力搜尋參考 普通搜尋每次查詢都需要 樸素演算法是一層一層往上找,倍增的話直接預處理出乙個 具體做法是 維護乙個 的關係來線性求出這個陣列 int anc n 31 int dep n 記錄節點深度 void dfs int u,int parent for int i 0 i g u size...

最近公共祖先 最近公共祖先(LCA)

如題,給定一棵有根多叉樹,請求出指定兩個點直接最近的公共祖先。輸入格式 第一行包含三個正整數n m s,分別表示樹的結點個數 詢問的個數和樹根結點的序號。接下來n 1行每行包含兩個正整數x y,表示x結點和y結點之間有一條直接連線的邊 資料保證可以構成樹 接下來m行每行包含兩個正整數a b,表示詢問...