BZOJ1787: [Ahoi2008]Meet 紧急集合(LCA)
2016-04-11 18:19
260 查看
这一道题中,每一次询问的答案就是这三个点,两两的LCA的异或和。至于这样为什么是对的呢?
我们先考虑是否一定有重复的LCA呢?
如果三个点在根节点的不同子树中,那么LCA都是根节点,三个都重复。
如果有两个在一个子树中,那么这两个与另外一个的LCA都是根节点。
如果三个都在一个子树中,可以归纳到以上两种情况。
然后考虑为什么是异或和。
如果三个LCA相同,那么一定是这个点无疑,等于异或和
如果有一个LCA与另外两个不同的时候,肯定要尽量避免两个人走同一段路。因为如果要走到三个点都在的深度最大的子树的根,即相同的LCA,那么必定会有两个人走过同一段路,所以去另一个,每个点都不会走重复的路径
我们先考虑是否一定有重复的LCA呢?
如果三个点在根节点的不同子树中,那么LCA都是根节点,三个都重复。
如果有两个在一个子树中,那么这两个与另外一个的LCA都是根节点。
如果三个都在一个子树中,可以归纳到以上两种情况。
然后考虑为什么是异或和。
如果三个LCA相同,那么一定是这个点无疑,等于异或和
如果有一个LCA与另外两个不同的时候,肯定要尽量避免两个人走同一段路。因为如果要走到三个点都在的深度最大的子树的根,即相同的LCA,那么必定会有两个人走过同一段路,所以去另一个,每个点都不会走重复的路径
/************************************************************** Problem: 1787 User: geng4512 Language: C++ Result: Accepted Time:1880 ms Memory:20336 kb ****************************************************************/ #include <cstdio> #define MAXN 500005 struct Node { int v, nxt; } e[MAXN << 1]; int hsn[MAXN], htp[MAXN], sz[MAXN]; int n, m, c, fa[MAXN], dep[MAXN], adj[MAXN]; inline void Add(int u, int v) { ++ c; e[c].v = v; e[c].nxt = adj[u]; adj[u] = c; } inline void GET(int &n) { static char c; n = 0; do c = getchar(); while('0' > c || c > '9'); do n=n*10+c-'0',c=getchar(); while('0' <= c && c <= '9'); } void dfs1(int u) { sz[u] = 1; for(int i = adj[u]; i; i = e[i].nxt) { if(sz[e[i].v]) continue; dep[e[i].v] = dep[u] + 1; fa[e[i].v] = u; dfs1(e[i].v); sz[u] += sz[e[i].v]; if(sz[e[i].v] > sz[hsn[u]]) hsn[u] = e[i].v; } } void dfs2(int u, int tp) { htp[u] = tp; if(hsn[u]) dfs2(hsn[u], tp); for(int i = adj[u]; i; i = e[i].nxt) if(!htp[e[i].v]) dfs2(e[i].v, e[i].v); } inline int LCA(int u, int v) { while(htp[u] != htp[v]) { if(dep[htp[u]] > dep[htp[v]]) u = fa[htp[u]]; else v = fa[htp[v]]; } return dep[u] > dep[v] ? v : u; } inline int dis(int u, int v) { return dep[u] - 2*dep[LCA(u, v)] + dep[v]; } int main() { scanf("%d%d", &n, &m); int u, v; for(int i = 1; i < n; ++ i) { GET(u); GET(v); Add(u, v); Add(v, u); } dfs1(1); dfs2(1, 1); int x, y, z, a, b, c; for(int i = 1; i <= m; ++ i) { GET(a); GET(b); GET(c); x = LCA(a, b); y = LCA(b, c); z = LCA(a, c); z = x ^ y ^ z; printf("%d %d\n", z, dis(a, z) + dis(b, z) + dis(c, z)); } return 0; }
相关文章推荐
- 面试积累 简历添加
- listview一键返回顶部悬浮按钮
- 友元函数第一次运用输出时间值
- 双重指针的用法
- Android PullToRrefresh 自定义下拉刷新动画 (listview、scrollview等)
- 软件测试——实验三
- 正则表达式格式化日期
- iOS常用加密方法(aes、md5、base64)
- Java注解的部分实现:动态代理
- Android自定义控件实战——仿淘宝商品浏览界面
- C++ 函数后加const
- Openstack Swift 原理、架构与 API 介绍
- 浏览器渲染引擎渲染页面过程
- You need to use a Theme.AppCompat theme
- 团队介绍及项目简介
- linux系统安装mysql
- LeetCode *** 328. Odd Even Linked List
- MYSQL--慢查询,卡死等处理
- [BZOJ 1096][ZJOI2007]仓库建设
- 杭电1106 分割字符串问题