祖孙询问 Lca-Tarjan
给定一棵包含 <span id="MathJax-Span-2" class="mrow"><span id="MathJax-Span-3" class="mi">nn 个节点的有根无向树,节点编号互不相同,但不一定是 <span id="MathJax-Span-5" class="mrow"><span id="MathJax-Span-6" class="mn">1<span id="MathJax-Span-7" class="mo">∼<span id="MathJax-Span-8" class="mi">n1∼n。
有 <span id="MathJax-Span-10" class="mrow"><span id="MathJax-Span-11" class="mi">mm 个询问,每个询问给出了一对节点的编号 <span id="MathJax-Span-13" class="mrow"><span id="MathJax-Span-14" class="mi">xx 和 <span id="MathJax-Span-16" class="mrow"><span id="MathJax-Span-17" class="mi">yy,询问 <span id="MathJax-Span-19" class="mrow"><span id="MathJax-Span-20" class="mi">xx 与 <span id="MathJax-Span-22" class="mrow"><span id="MathJax-Span-23" class="mi">yy 的祖孙关系。
输入格式
输入第一行包括一个整数 表示节点个数;
接下来 <span id="MathJax-Span-25" class="mrow"><span id="MathJax-Span-26" class="mi">nn 行每行一对整数 <span id="MathJax-Span-28" class="mrow"><span id="MathJax-Span-29" class="mi">aa 和 <span id="MathJax-Span-31" class="mrow"><span id="MathJax-Span-32" class="mi">bb,表示 <span id="MathJax-Span-34" class="mrow"><span id="MathJax-Span-35" class="mi">aa 和 <span id="MathJax-Span-37" class="mrow"><span id="MathJax-Span-38" class="mi">bb 之间有一条无向边。如果 <span id="MathJax-Span-40" class="mrow"><span id="MathJax-Span-41" class="mi">bb 是 <span id="MathJax-Span-43" class="mrow"><span id="MathJax-Span-44" class="mo">−<span id="MathJax-Span-45" class="mn">1−1,那么 <span id="MathJax-Span-47" class="mrow"><span id="MathJax-Span-48" class="mi">aa 就是树的根;
第 <span id="MathJax-Span-50" class="mrow"><span id="MathJax-Span-51" class="mi">n<span id="MathJax-Span-52" class="mo">+<span id="MathJax-Span-53" class="mn">2n+2 行是一个整数 <span id="MathJax-Span-55" class="mrow"><span id="MathJax-Span-56" class="mi">mm 表示询问个数;
接下来 <span id="MathJax-Span-58" class="mrow"><span id="MathJax-Span-59" class="mi">mm 行,每行两个不同的正整数 <span id="MathJax-Span-61" class="mrow"><span id="MathJax-Span-62" class="mi">xx 和 <span id="MathJax-Span-64" class="mrow"><span id="MathJax-Span-65" class="mi">yy,表示一个询问。
输出格式
对于每一个询问,若 <span id="MathJax-Span-67" class="mrow"><span id="MathJax-Span-68" class="mi">xx 是 <span id="MathJax-Span-70" class="mrow"><span id="MathJax-Span-71" class="mi">yy 的祖先则输出 <span id="MathJax-Span-73" class="mrow"><span id="MathJax-Span-74" class="mn">11,若 <span id="MathJax-Span-76" class="mrow"><span id="MathJax-Span-77" class="mi">yy 是 <span id="MathJax-Span-79" class="mrow"><span id="MathJax-Span-80" class="mi">xx 的祖先则输出 <span id="MathJax-Span-82" class="mrow"><span id="MathJax-Span-83" class="mn">22,否则输出 <span id="MathJax-Span-85" class="mrow"><span id="MathJax-Span-86" class="mn">00。
数据范围
<span id="MathJax-Span-88" class="mrow"><span id="MathJax-Span-89" class="mn">1<span id="MathJax-Span-90" class="mo">≤<span id="MathJax-Span-91" class="mi">n<span id="MathJax-Span-92" class="mo">,<span id="MathJax-Span-93" class="mi">m<span id="MathJax-Span-94" class="mo">≤<span id="MathJax-Span-95" class="mn">4<span id="MathJax-Span-96" class="mo">×<span id="MathJax-Span-97" class="msubsup"><span id="MathJax-Span-98" class="mn">10<span id="MathJax-Span-99" class="mn">41≤n,m≤4×104,
<span id="MathJax-Span-101" class="mrow"><span id="MathJax-Span-102" class="mn">1<span id="MathJax-Span-103" class="mo">≤<span id="MathJax-Span-104" class="texatom"><span id="MathJax-Span-105" class="mrow"><span id="MathJax-Span-106" class="mo">每<span id="MathJax-Span-107" class="texatom"><span id="MathJax-Span-108" class="mrow"><span id="MathJax-Span-109" class="mo">个<span id="MathJax-Span-110" class="texatom"><span id="MathJax-Span-111" class="mrow"><span id="MathJax-Span-112" class="mo">节<span id="MathJax-Span-113" class="texatom"><span id="MathJax-Span-114" class="mrow"><span id="MathJax-Span-115" class="mo">点<span id="MathJax-Span-116" class="texatom"><span id="MathJax-Span-117" class="mrow"><span id="MathJax-Span-118" class="mo">的<span id="MathJax-Span-119" class="texatom"><span id="MathJax-Span-120" class="mrow"><span id="MathJax-Span-121" class="mo">编<span id="MathJax-Span-122" class="texatom"><span id="MathJax-Span-123" class="mrow"><span id="MathJax-Span-124" class="mo">号<span id="MathJax-Span-125" class="mo">≤<span id="MathJax-Span-126" class="mn">4<span id="MathJax-Span-127" class="mo">×<span id="MathJax-Span-128" class="msubsup"><span id="MathJax-Span-129" class="mn">10<span id="MathJax-Span-130" class="mn">41≤每个节点的编号≤4×104
输入样例:
10
234 -1
12 234
13 234
14 234
15 234
16 234
17 234
18 234
19 234
233 19
5
234 233
233 12
233 13
233 15
233 19
输出样例:
1
0
0
0
2
分析
Tarjan 算法
是一种 离线算法
,需要使用 并查集
记录某个结点的祖先结点。
当一个节点回溯之后,它和还未被标记有lca且已经回溯过的所有节点的lca,是那个还没回溯,且在那些节点链上深度最低的节点
并查集 实现 找每个节点链上深度最低的点(简称每个节点的根),在每次回溯完之后都更新成它的根节点,然后假如说链长度>2 ,就会实现子子节点的根是子节点,子节点的根是根节点,由于并查集更改了子节点的根,也就同时改变了子子节点的根,变成了根节点。
//#define int ll const int N = 80010; int n,m; int h[N],ne[N],e[N],w[N],idx,p[N]; int root; int res[N],st[N]; V<pii>query[N]; pii request[N]; void add(int a,int b) { e[idx] = b,ne[idx] = h[a],h[a] = idx ++ ; } int find(int x) { return x == p[x] ? x : p[x] = find(p[x]); } void tarjan(int u) { st[u] = 1; for(int i = h[u];~i;i=ne[i]) { if(!st[e[i]]) { tarjan(e[i]); p[e[i]] = u; } } for(auto item:query[u]) { int j = item.x; int id = item.y; if(st[j] == 2) {//如果两个节点都已经回溯过了 int fa = find(j);//它们的最近公共祖先就是它们遍历过程中深度最低的点 res[id] = fa;// } } st[u] = 2; } void solve() { // cin>>n>>m; cin>>n; ms(h,-1); fo(i,1,N) p[i] = i; fo(i,1,n) { int a,b;cin>>a>>b; if(b == -1)root = a; else add(a,b),add(b,a); } cin>>m; fo(i,1,m) { int a,b;cin>>a>>b; query[a].pb({b,i}); query[b].pb({a,i}); request[i] = {a,b}; } tarjan(root); fo(i,1,m) { if(res[i] == request[i].x) puts("1"); else if(res[i] == request[i].second) puts("2"); else puts("0"); } rt; } signed main(){ AC(); clapping();TLE; // while(cin>>n,n) // while(cin>>n>>m,n,m) // int t;cin>>t;while(t -- ) solve(); // {solve(); } return 0; }