\(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,表示詢問...