最近公共祖先 - 离线处理
Posted redips
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了最近公共祖先 - 离线处理相关的知识,希望对你有一定的参考价值。
hiho1067
问树上两个点的最近公共祖先
-------------------------------------------------------------------------------------------------------
第一次写所谓的离线算法,不是来一个询问就处理一下,而是在扫描树的过程中每扫到一个点就处理和这个点相关的询问。
因为这个点的祖先肯定都访问过一次了,且所有标记为1的点都是这个点的祖先
第一次扫到这个点时标记为1,扫完这个点的所有子节点后标记为2;
关于当前点a的询问有三种情况:
1.另外一个点b的标记为0,暂时无法判断;
2.另外一个点b的标记为1,说明b为a的祖先,输出b;
3.另外一个点b的标记为2,找到离b最近的标记为1的点;
关于3,采用并查集维护,开始时每个点的[最近标记为1的点]都设成自己。从叶子向上,每标记一个点为2时,就把他及他的子孙挂到他的父节点上。
注意:扫到一个点的时候一定要先处理和它相关的询问,然后再dfs这个节点,如果先dfs这个节点,再处理询问会出错。因为这个时候他的标记变成2了,他已经挂到父节点上了,如果询问他及他的子孙节点的最近祖先应该返回他,但是这时会返回他的父亲。
#include <set>
#include <map>
#include <stack>
#include <queue>
#include <cmath>
#include <vector>
#include <string>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#define MAX(a,b) ((a)>=(b)?(a):(b))
#define MIN(a,b) ((a)<=(b)?(a):(b))
#define OO 0x0fffffff
using namespace std;
typedef long long LL;
const int N = 100100;
struct Edge{ int to,next,id; };
int father[N];
int ans[N],vis[N];
int headsq[N],headst[N];
Edge tree[N*2],query[N*2];
int eidq = 0;
int eidt = 0;
void addQuery(int a,int b,int id){
query[eidq].to = b;
query[eidq].next = headsq[a];
query[eidq].id = id;
headsq[a] = eidq++;
query[eidq].to = a;
query[eidq].next = headsq[b];
query[eidq].id = id;
headsq[b] = eidq++;
ans[id]=-1;
}
void addEdge(int a,int b){
tree[eidt].to = b;
tree[eidt].next = headst[a];
headst[a] = eidt++;
}
int find(int id){
int fid = father[id];
if(fid==id) return fid;
return (father[id] = find(fid));
}
void dfs(int id,int fid){
for(int curId=headst[id];curId!=-1;curId=tree[curId].next){
int to = tree[curId].to;
vis[to] = 1;
for(int qid=headsq[to];qid!=-1;qid=query[qid].next){
if(ans[query[qid].id]!=-1) continue;
int curq = query[qid].to;
if(vis[curq]==1) {
ans[query[qid].id]=curq;
}
else if(vis[curq]==2){
ans[query[qid].id]=find(curq);
}
}
dfs(to,id);
}
vis[id] = 2;
father[id] = father[fid];
}
int n,m;
int id1,id2;
map<string,int> m1;
map<int,string> m2;
char name1[64],name2[64];
int main(){
memset(vis,0,sizeof(vis));
memset(headsq,-1,sizeof(headsq));
memset(headst,-1,sizeof(headst));
cin>>n;
int cnt = 0;
for(int i=0;i<n;i++){
cin>>name1>>name2;
if(!(m1.count(name1))){
m1[name1] = cnt;
m2[cnt] = name1;
id1 = cnt++;
}
else id1 = m1[name1];
if(!(m1.count(name2))){
m1[name2] = cnt;
m2[cnt] = name2;
id2 = cnt++;
}
else id2 = m1[name2];
addEdge(id1,id2);
}
cin>>m;
for(int i=0;i<m;i++){
cin>>name1>>name2;
addQuery(m1[name1],m1[name2],i);
}
for(int i=0;i<=n;i++) father[i]=i;
vis[0]=1;
dfs(0,0);
for(int i=0;i<m;i++){
cout<<m2[ans[i]]<<endl;
};
return 0;
}
以上是关于最近公共祖先 - 离线处理的主要内容,如果未能解决你的问题,请参考以下文章