题目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;
}

离线LCA学习的更多相关文章

  1. HDU 5044 离线LCA算法

    昨天写了HDU 3966 ,本来这道题是很好解得,结果我想用离线LCA 耍一把,结果发现离线LCA 没理解透,错了好多遍,终得AC ,这题比起 HDU 3966要简单,因为他不用动态查询.但是我还是错 ...

  2. 【图论】tarjan的离线LCA算法

    百度百科 Definition&Solution 对于求树上\(u\)和\(v\)两点的LCA,使用在线倍增可以做到\(O(nlogn)\)的复杂度.在NOIP这种毒瘤卡常比赛中,为了代码的效 ...

  3. HDU 2586 How far away ? 离线lca模板题

    How far away ? Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)To ...

  4. hihoCoder #1067 : 最近公共祖先·二 [ 离线LCA tarjan ]

    传送门: #1067 : 最近公共祖先·二 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 上上回说到,小Hi和小Ho用非常拙劣——或者说粗糙的手段山寨出了一个神奇的网站 ...

  5. poj1470 Closest Common Ancestors [ 离线LCA tarjan ]

    传送门 Closest Common Ancestors Time Limit: 2000MS   Memory Limit: 10000K Total Submissions: 14915   Ac ...

  6. SPOJ 10628 Count on a tree(Tarjan离线LCA+主席树求树上第K小)

    COT - Count on a tree #tree You are given a tree with N nodes.The tree nodes are numbered from 1 to  ...

  7. POJ-1330--Nearest Common Ancestors(离线LCA)

    LCA离线算法 它需要一次输入所有的询问,然后有根节点开始进行深度优先遍历(DFS),在深度优先遍历的过程中,进行并查集的操作,同时查询询问,返回结果. 题意: 求A ,B两点的最近公共祖先 分析: ...

  8. 关于Tarjan(3)——离线LCA

    LCA(最近公共祖先),指对于一棵树上任意两个节点往上走最早都能到达的节点. 求LCA有两种方法,一种是倍增,另一种则是Tarjan........ Tarjan巧妙利用并查集的思想: 这里的Tarj ...

  9. HDU 2586.How far away ?-离线LCA(Tarjan)

    2586.How far away ? 这个题以前写过在线LCA(ST)的,HDU2586.How far away ?-在线LCA(ST) 现在贴一个离线Tarjan版的 代码: //A-HDU25 ...

随机推荐

  1. [Go] 通过 17 个简短代码片段,切底弄懂 channel 基础

    关于管道 Channel Channel 用来同步并发执行的函数并提供它们某种传值交流的机制. Channel 的一些特性:通过 channel 传递的元素类型.容器(或缓冲区)和 传递的方向由“&l ...

  2. 用Qemu搭建x86_64学习环境

    作者信息 作者:彭东林 邮箱:pengdonglin137@163.com QQ:405728433 软件平台 主机: Ubuntu14.04 64位版本 模拟器:Qemu-2.8.0 Linux内核 ...

  3. 使用FTP发布和更新Windows Azure网站

    在Windows Azure中,FTP的用户名和密码与管理门户的用户名和密码不一样,需要另外设置. →依次点击左侧的"网站",网站名称,右侧的"设置部署凭据", ...

  4. Delphi XE2 compiler performance

    原文: http://blog.barrkel.com/2011/10/delphi-xe2-compiler-performance.html Delphi XE2 compiler perform ...

  5. cocos2d-x CC_SYNTHESIZE_READONLY

    //定义一个只读属性Label,在类定义中可以使用this->getLabel来访问     CC_SYNTHESIZE_READONLY(cocos2d::CCLabelTTF*,_label ...

  6. Java判断多个时间段是否重叠(重叠区间个数)

    import java.util.ArrayList; import java.util.Collections; import java.util.List; /** * 判断多个时间段是否出现重叠 ...

  7. Java并发编程的艺术(五)——中断

    什么是中断? 在Java中没有办法立即停止一条线程,然而停止线程却显得尤为重要,如取消一个耗时操作.因此,Java提供了一种用于停止线程的机制——中断. 中断只是一种协作机制,Java没有给中断增加任 ...

  8. Eclipse with ADT的安装和配置

    我们从安卓官方网站(https://developer.android.com/sdk/index.html#download)下载下来的eclipse是捆绑好了ADT的,所以不用自己安装插件,十分方 ...

  9. 使用Bootstrap后,关于IE与Chrome显示字体的问题

    在做日志系统时,使用了Bootstrap,然后通过浏览器查看的页面效果如下 对比可以看到,同样的字体,IE显示的圆润些,而Chrome字体则丑很多.因为Chrome默认用宋体 在http://v3.b ...

  10. Verilog 加法器和减法器(4)

    类似于行波进位加法器,用串联的方法也能够实现多位二进制数的减法操作.  比如下图是4位二进制减法逻辑电路图. 8位二进制减法的verilog代码如下: module subn(x, y, d,cin) ...