离线LCA学习

时间:2023-03-08 20:46:58

题目1 : 近期公共祖先·二

时间限制:10000ms
单点时限:1000ms
内存限制:256MB

描写叙述

上上回说到,小Hi和小Ho用很拙劣——或者说粗糙的手段山寨出了一个奇妙的站点,这个站点能够计算出某两个人的全部共同祖先中辈分最低的一个是谁。

远在美国的他们利用了一些奇异的技术获得了国内很多人的相关信息,而且搭建了一个小小的站点来应付来自四面八方的请求。

但正如我们所能想象到的……这样一个简单的算法并不能支撑住很大的訪问量,所以摆在小Hi和小Ho面前的无非两种选择:

其一是购买更为昂贵的server。通过提高计算机性能的方式来满足需求——但小Hi和小Ho并没有那么多的钱;其二则是改进他们的算法,通过提高计算机性能的利用率来满足需求——这个主意似乎听起来更加靠谱。

于是为了他们第一个在线产品的顺利运作。小Hi决定对小Ho进行紧急训练——好好的改动一番他们的算法。

而为了更好的向小Ho讲述这个问题。小Hi将这个问题抽象成了这个样子:如果现小Ho如今知道了N对父子关系——父亲和儿子的名字,而且这N对父子关系中涉及的全部人都拥有一个共同的祖先(这个祖先出如今这N对父子关系中)。他须要对于小Hi的若干次提问——每次提问为两个人的名字(这两个人的名字在之前的父子关系中出现过),告诉小Hi这两个人的全部共同祖先中辈分最低的一个是谁?

提示一:老老实实分情况讨论就不会出错的啦!

提示二:并查集事实上长得非常像一棵树你们不认为么?

输入

每一个測试点(输入文件)有且仅有一组測试数据。

每组測试数据的第1行为一个整数N,意义如前文所述。

每组測试数据的第2~N+1行,每行分别描写叙述一对父子关系,当中第i+1行为两个由大写和小写字母组成的字符串Father_i, Son_i。分别表示父亲的名字和儿子的名字。

每组測试数据的第N+2行为一个整数M。表示小Hi总共询问的次数。

每组測试数据的第N+3~N+M+2行,每行分别描写叙述一个询问,当中第N+i+2行为两个由大写和小写字母组成的字符串Name1_i, Name2_i。分别表示小Hi询问中的两个名字。

对于100%的数据,满足N<=10^5。M<=10^5, 且数据中全部涉及的人物中不存在两个名字同样的人(即姓名唯一的确定了一个人),全部询问中出现过的名字均在之前所描写叙述的N对父子关系中出现过,第一个出现的名字所确定的人是其它全部人的公共祖先。

输出

对于每组測试数据,对于每一个小Hi的询问,依照在输入中出现的顺序,各输出一行,表示查询的结果:他们的全部共同祖先中辈分最低的一个人的名字。

例子输入
4
Adam Sam
Sam Joey
Sam Micheal
Adam Kevin
3
Sam Sam
Adam Sam
Micheal Kevin
例子输出
Sam
Adam
Adam

离线代码例如以下:

/*************************************************************************
> File Name: t.cpp
> Author: acvcla
> QQ:
> Mail: acvcla@gmail.com
> Created Time: 2014年10月16日 星期四 23时22分13秒
************************************************************************/
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<vector>
#include<cstring>
#include<map>
#include<queue>
#include<stack>
#include<string>
#include<cstdlib>
#include<ctime>
#include<set>
#include<math.h>
using namespace std;
typedef long long LL;
const int maxn = 1e5 + 10;
#define rep(i,a,b) for(int i=(a);i<=(b);i++)
#define pb push_back
map<string,int>f1;
map<int,string>f2;
std::vector<int>G[maxn];
map<pair<int,int>,int>ans;
std::vector<int>query[maxn];
int ql[maxn],qr[maxn];
int col[maxn],p[maxn];
int findx(int x){
return p[x]==x? x:p[x]=findx(p[x]);
}
void Union(int u,int v){
p[findx(v)]=findx(u);
}
void Init(int n){
for(int i=0;i<=n;i++){
query[i].clear();
G[i].clear();
col[i]=0;
p[i]=i;
}
f1.clear();
f2.clear();
ans.clear();
}
void lca(int u){
for(int i=0;i<G[u].size();i++){
lca(G[u][i]);
Union(u,G[u][i]);
}
col[u]=1;
for(int i=0;i<query[u].size();++i){
int v=query[u][i];
if(col[v]){
ans[make_pair(u,v)]=findx(v);
}
}
}
int main(){
ios_base::sync_with_stdio(false);
cin.tie(0);
int n,m;
while(cin>>n){
string fa,son;
int tot=0;
Init(n+3);
for(int i=1;i<=n;i++){
cin>>fa>>son;
if(!f1[fa]){
f1[fa]=++tot;
f2[tot]=fa;
}if(!f1[son]){
f1[son]=++tot;
f2[tot]=son;
}
//cout<<f1[fa]<<' '<<f1[son]<<endl;
G[f1[fa]].pb(f1[son]);
}
cin>>m;
for(int i=0;i<m;i++){
cin>>fa>>son;
ql[i]=f1[fa];
qr[i]=f1[son];
query[ql[i]].pb(qr[i]);
query[qr[i]].pb(ql[i]);
}
lca(1);
for(int i=0;i<m;i++){
int x=0;
x=ans[make_pair(ql[i],qr[i])];
if(!x)x=ans[make_pair(qr[i],ql[i])];
cout<<f2[x]<<endl;
}
}
return 0;
}