#1067 : 最近公共祖先·二
来源:互联网 发布:json和ajax结合使用 编辑:程序博客网 时间:2024/05/17 18:03
题目链接 及 思路参考
输入
每个测试点(输入文件)有且仅有一组测试数据。
每组测试数据的第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的询问,按照在输入中出现的顺序,各输出一行,表示查询的结果:他们的所有共同祖先中辈分最低的一个人的名字。
思路:
在最近公共祖先一中,每一次询问都查找一次。
询问量大时:求解最近公共祖先的离线算法。一次性收集若干询问之后才能通过这个算法一同计算出答案
深度优先搜索的过程中对结点染色,如果发现当前访问的结点是涉及到某个询问,那么就看这个询问中另一个结点的颜色,如果是白色,则留待之后处理,如果是灰色,那么最近公共祖先必然就是这个灰色结点,如果是黑色,那么最近公共祖先就是这个黑色结点向上的第一个灰色结点
深度优先搜索的过程中对结点染色,如果发现当前访问的结点是涉及到某个询问,那么就看这个询问中另一个结点的颜色,如果是白色,则留待之后处理,如果是灰色,那么最近公共祖先必然就是这个灰色结点,如果是黑色,那么最近公共祖先就是这个黑色结点向上的第一个灰色结点
通过graph进行dfs,edge存查询的所有连接(双向),Edge的id表示查询顺序(1,2...)v表示查询的另一点
结合并查集:每个结点最开始都是一个独立的集合,每当一个结点由灰转黑的时候,就将它所在的集合合并到其父亲结点所在的集合中去。这样无论什么时候,任意一个黑色结点所在集合的代表元素就是这个结点向上的第一个灰色结点
AC代码:
class Edge {int v,id;Edge(int v,int id){ this.v = v; this.id = id; }}public class Main {static int n;static int m;static int[] ans;static int[] father; //存father的idstatic boolean[] hasfa;static int[] color; // 表颜色,0白色,1灰色,2黑色static Map<Integer,List<Integer>> graph; // 存孩子static Map<Integer, List<Edge>> edge;static Map<String, Integer> idx; // string与id对应static int id = 0;static String[] str; // 输出时返回namepublic static void main(String[] args) {input();solve();}/* * 输入 */public static void input() {Scanner in = new Scanner(System.in);n = Integer.parseInt(in.nextLine());idx = new HashMap<String, Integer>();hasfa = new boolean[n * 2]; // 注意hasfa的size有可能超过n + 1str = new String[n * 2];color = new int[n * 2];father = new int[n * 2];graph = new HashMap<Integer,List<Integer>>();edge = new HashMap<Integer, List<Edge>>();ans = new int[n];for (int i = 0; i < n; i++) {String[] s = in.nextLine().split(" ");int id1 = get_idx(s[0]);int id2 = get_idx(s[1]);hasfa[id2] = true;father[i] = i;if (!graph.containsKey(id1)) {List<Integer> l = new ArrayList<Integer>();graph.put(id1,l);}graph.get(id1).add(id2);}m = Integer.parseInt(in.nextLine());for (int i = 1; i <= m; i++) {String[] s = in.nextLine().split(" ");int idx1 = get_idx(s[0]); int idx2 = get_idx(s[1]); if (!edge.containsKey(idx1)) { List<Edge> l = new ArrayList<Edge>(); edge.put(idx1, l);} edge.get(idx1).add(new Edge(idx2, i)); if (!edge.containsKey(idx2)) { List<Edge> l = new ArrayList<Edge>(); edge.put(idx2, l);}edge.get(idx2).add(new Edge(idx1, i));}in.close();}public static void solve() {int root = -1;for (int i = 1; i <= n; i++) {if (!hasfa[i]) {root = i;}}tarjan(root); // 从根节点开始dfs// 输出结果for (int i = 1; i <= m; i++) {System.out.println(str[ans[i]]);}}public static void tarjan (int u) {color[u] = 1;if (edge.containsKey(u)) {for(int i = 0; i < edge.get(u).size(); i++) { // 遍历所有查询,是否有当前idint ID = edge.get(u).get(i).id; // 指查询顺序,1开始if (ans[ID] != 0) { continue;}int v = edge.get(u).get(i).v;// 0代表未访问过if (color[v] == 0) {continue;} else if (color[v] == 1) { // 1代表正在访问,所以u和v的公共祖先就是vans[ID] = v;} else if (color[v] == 2) { // 2表示访问完毕的节点,所以u和v的公共祖先就是v当前的祖先ans[ID] = Find(v);}}}if (!graph.containsKey(u)) {return;}for (int i = 0; i < graph.get(u).size(); i++) {int vv = graph.get(u).get(i);tarjan(vv);// 一个节点dfs完毕,标记vv为访问完毕的点,并更新父节点color[vv] = 2;father[vv] = u; // 注意这里更新father}}/* * 寻找x的祖先 */public static int Find(int x) {return x != father[x] ? father[x] = Find(father[x]) : father[x]; }// 获得name对应的idpublic static int get_idx(String name){ if(idx.containsKey(name)) return idx.get(name); idx.put(name, ++id); str[id] = name; return id;}}
0 0
- [HiHoCoder]#1067 : 最近公共祖先·二
- 1067 : 最近公共祖先·二
- hihoCoder 1067 最近公共祖先·二
- [HihoCoder]#1067 : 最近公共祖先·二
- #1067 : 最近公共祖先·二
- [hiho]#1067 : 最近公共祖先·二 离线算法
- hihocoder1067[最近公共祖先·二] DFS序+ST表
- hihocoder 1067 最近公共祖先·二(tarjan LCA 离线算法O(n))
- hihocoder 1067 最近公共祖先·二 并查集+stl
- hihoCoder_#1067_最近公共祖先·二(LCA+tarjan模板)
- HIHO #1067 : 最近公共祖先·二(并查集+dfs LCA离线算法)
- hihoCoder 1067 : 最近公共祖先·二(map+离线Tarjan算法)
- hihocoder 1067(最近公共祖先tarjin)
- hihocoder:#1062 : 最近公共祖先·一
- [hihoCoder]#1062 : 最近公共祖先·一
- 1062 : 最近公共祖先·一
- #1069 : 最近公共祖先·三
- hihoCoder 1062 最近公共祖先·一
- Leetcode 38 Count and Say
- 单一职责原则(设计模式_03)
- Android 颜色渲染 PorterDuff及Xfermode详解
- 数据结构与算法笔记 lesson 20 二叉树遍历
- opencv摘要
- #1067 : 最近公共祖先·二
- 程序第一次启动从欢迎页跳到引导页,下次再启动直接从欢迎页跳转到主页
- ios编译linphone 开启x264编译
- <ROS> Ubuntu14.04下ROS indigo Eclipse开发环境搭建
- Error:(1, 0) Plugin with id ‘com.android.application’ not found
- Python模块WSGI详解
- M12D12WEB前端笔记(王)
- Spring RestTemplate: 比httpClient更优雅的Restful URL访问, java HttpPost with header,Spring RestTemplate在spr
- RCNN总结