【HIHOCODER 1067】最近公共祖先·二(LCA)
2017-10-15 20:43
155 查看
描述
上上回说到,小Hi和小Ho用非常拙劣——或者说粗糙的手段山寨出了一个神奇的网站,这个网站可以计算出某两个人的所有共同祖先中辈分最低的一个是谁。远在美国的他们利用了一些奇妙的技术获得了国内许多人的相关信息,并且搭建了一个小小的网站来应付来自四面八方的请求。但正如我们所能想象到的……这样一个简单的算法并不能支撑住非常大的访问量,所以摆在小Hi和小Ho面前的无非两种选择:
其一是购买更为昂贵的服务器,通过提高计算机性能的方式来满足需求——但小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
题解
题解:http://hihocoder.com/problemset/problem/1067#include <map> #include <cmath> #include <cstdio> #include <complex> #include <cstring> #include <cstdlib> #include <iostream> #include <algorithm> #define ll long long #define inf 0 #define PI acos(-1) #define bug puts("here") #define REP(i,x,n) for(int i=x;i<=n;i++) #define DEP(i,n,x) for(int i=n;i>=x;i--) #define mem(a,x) memset(a,x,sizeof(a)) typedef unsigned long long ull; using namespace std; inline int read(){ int x=0,f=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} return x*f; } inline void Out(int a){ if(a<0) putchar('-'),a=-a; if(a>=10) Out(a/10); putchar(a%10+'0'); } const int MOD=1000000007; const int N=100000+5; int fa ,head ,head2 ,tot,tot2; bool in ; map<int,int>vis2; int n,m; struct node{ int to,nex,id; node(int u,int v,int ti=0):to(u),nex(v),id(ti){} node(){} }Path[N<<1],query[N<<1]; void Addedge(int u,int v){ Path[++tot]=node(v,head[u]); head[u]=tot; } void Addedge2(int u,int v,int id){ query[++tot2]=node(v,head2[u],id); head2[u]=tot2; } int hashstr(char* str){ int res=0; REP(i,0,strlen(str)-1){ res=(res*233+str[i])%MOD; } return res; } int find(int x){return fa[x]==-1?x:fa[x]=find(fa[x]);} bool vis ; int ancestor ,ans ; char name [20]; void lca(int u){ vis[u]=true; ancestor[u]=u; for(int i=head[u];i;i=Path[i].nex){ int v=Path[i].to; if(vis[v]) continue; lca(v); int f1=find(u),f2=find(v); if(f1!=f2) fa[f2]=f1; ancestor[find(u)]=u; } for(int i=head2[u];i;i=query[i].nex){ int v=query[i].to; if(vis[v]){ ans[query[i].id]=ancestor[find(v)]; } } } int main(){ n=read(); char s1[20],s2[20]; memset(head,-1,sizeof(head)); memset(head2,-1,sizeof(head2)); memset(fa,-1,sizeof(fa)); int cnt=0; REP(i,1,n){ scanf("%s%s",s1,s2); int ha1=hashstr(s1); int ha2=hashstr(s2); if(!vis2[ha1]) vis2[ha1]=++cnt,strcpy(name[cnt],s1); if(!vis2[ha2]) vis2[ha2]=++cnt,strcpy(name[cnt],s2); ha1=vis2[ha1];ha2=vis2[ha2]; Addedge(ha1,ha2); Addedge(ha2,ha1); in[ha2]=true; } m=read(); REP(i,1,m){ scanf("%s%s",s1,s2); int ha1=hashstr(s1); int ha2=hashstr(s2); ha1=vis2[ha1];ha2=vis2[ha2]; Addedge2(ha1,ha2,i); Addedge2(ha2,ha1,i); } int root=1; REP(i,1,n){ if(!in[i])root=i; } lca(root); REP(i,1,m){ printf("%s\n",name[ans[i]]); } return 0; }
相关文章推荐
- hihocoder 1067 最近公共祖先·二(tarjan LCA 离线算法O(n))
- hihoCoder_#1067_最近公共祖先·二(LCA+tarjan模板)
- hihocoder1062 最近公共祖先·一
- hihoCoder1067 最近公共祖先离线查询 dfs + 并查集
- hihocoder1069 最近公共祖先·三(trajin算法)(并查集)
- hihoCoder 1062 : 最近公共祖先·一(map+lca)
- HihoCoder 1067 最近公共祖先(ST离线算法)
- hihoCoder 1067 最近公共祖先·二
- [HIHO1062] 最近公共祖先·一(lca, 并查集, 二分, 神trick)
- hihocoder1062 最近公共祖先·一
- [HihoCoder]#1067 : 最近公共祖先·二
- hihoCoder 1067 : 最近公共祖先·二(map+离线Tarjan算法)
- hihocoder1067[最近公共祖先·二] DFS序+ST表
- Hihocoder 1067 最近公共祖先二
- 最近公共祖先lca离线
- [笔记]LCA最近公共祖先---倍增在线算法
- hihocoder #1069 : 最近公共祖先·三(ST求LCA)
- POJ 1330 LCA最近公共祖先 离线tarjan算法
- LCA(最近公共祖先)tarjan算法学习笔记
- 最近公共祖先LCA(Tarjan算法)的思考和算法实现