P3379 【模板】最近公共祖先(LCA)(LCT)
阿新 • • 發佈:2019-01-12
\(\color{#0066ff}{ 題目描述 }\)
如題,給定一棵有根多叉樹,請求出指定兩個點直接最近的公共祖先。
\(\color{#0066ff}{輸入格式}\)
第一行包含三個正整數N、M、S,分別表示樹的結點個數、詢問的個數和樹根結點的序號。
接下來N-1行每行包含兩個正整數x、y,表示x結點和y結點之間有一條直接連線的邊(資料保證可以構成樹)。
接下來M行每行包含兩個正整數a、b,表示詢問a結點和b結點的最近公共祖先。
\(\color{#0066ff}{輸出格式}\)
輸出包含M行,每行包含一個正整數,依次為每一個詢問的結果。
\(\color{#0066ff}{輸入樣例}\)
5 5 4
3 1
2 4
5 1
1 4
2 4
3 2
3 5
1 2
4 5
\(\color{#0066ff}{輸出樣例}\)
4
4
1
4
4
\(\color{#0066ff}{資料範圍與提示}\)
時空限制:1000ms,128M
資料規模:
對於30%的資料:N<=10,M<=10
對於70%的資料:N<=10000,M<=10000
對於100%的資料:N<=500000,M<=500000
\(\color{#0066ff}{ 題解 }\)
拿LCT只為了求個LCA
有毒啊
access的時候記錄一下上一個點(下一個鏈尾)
access第二個點的時候,最後一次的那個鏈的接觸點就是LCA
// luogu-judger-enable-o2 #include<bits/stdc++.h> using namespace std; #define LL long long LL in() { char ch; int x = 0, f = 1; while(!isdigit(ch = getchar()))(ch == '-') && (f = -f); for(x = ch ^ 48; isdigit(ch = getchar()); x = (x << 1) + (x << 3) + (ch ^ 48)); return x * f; } const int maxn = 5e5 + 5; struct LCT { protected: struct node { node *ch[2], *fa; int rev; node(int rev = 0): rev(rev) { ch[0] = ch[1] = fa = NULL; } bool ntr() { return fa && (fa->ch[1] == this || fa->ch[0] == this); } bool isr() { return fa->ch[1] == this; } void trn() { std::swap(ch[0], ch[1]); rev ^= 1; } void dwn() { if(rev) { if(ch[0]) ch[0]->trn(); if(ch[1]) ch[1]->trn(); rev = 0; } } }s[maxn], *t[maxn], *lst; int top; void rot(node *x) { node *y = x->fa, *z = y->fa; int k = x->isr(); node *w = x->ch[!k]; if(y->ntr()) z->ch[y->isr()] = x; x->ch[!k] = y, y->ch[k] = w; y->fa = x, x->fa = z; if(w) w->fa = y; } void splay(node *o) { t[top = 1] = o; while(t[top]->ntr()) t[top + 1] = t[top]->fa, top++; while(top) t[top--]->dwn(); while(o->ntr()) { if(o->fa->ntr()) rot(o->isr() ^ o->fa->isr()? o : o->fa); rot(o); } } void access(node *x) { for(node *y = NULL; x; x = (y = x)->fa) splay(x), x->ch[1] = y, lst = x; } void makeroot(node *x) { access(x), splay(x), x->trn(); } node *findroot(node *x) { access(x), splay(x); while(x->dwn(), x->ch[0]) x = x->ch[0]; return splay(x), x; } node *getLCA(node *x, node *y) { return access(x), access(y), lst; } void link(node *x, node *y) { makeroot(x), x->fa = y; } public: void link(int x, int y) { link(s + x, s + y); } int LCA(int x, int y) { return getLCA(s + x, s + y) - s; } void makeroot(int x) { makeroot(s + x); } }v; int main() { int n = in(), m = in(), s = in(); for(int i = 1; i < n; i++) v.link(in(), in()); v.makeroot(s); while(m --> 0) printf("%d\n", v.LCA(in(), in())); return 0; }