0921 LCA练习
1.poj 1330
数据结构中的树,在计算机科学中是非常重要的,例如我们来看看下面这棵树:

在图中我们对每个节点都有编号了。 8号节点是这棵树的根。我们定义,一个子节点向它的根节点的路径上,任意一个节点都称为它的祖先。例如, 4号节点是16号节点的祖先。而10号节点同样也是16号的祖先。事实上,16号的祖先有8,4,10,16共四个。另外8, 4, 6,7都是7号节点的祖先,所以7号和16号的公共祖先是4和8号,而在这两个里面,4号是距离7和16最近的一个,所以我们称7号和16号的最近公共祖先是4号。
再例如,2和3的最近公共祖先是10,再例如6和13的是8。
现在你需要编写一个程序,在一棵树中找出指定两个节点的最近公共祖先
Input
第一行输入T表示有T组数据。每组第一行是N表示这棵树有多少个节点,其中 2<=N<=10,000。 节点用正整数1, 2,..., N表示。 接下来的 N -1 行表示这棵树的边,每行两个数,都是节点编号,前一个是后一个的父节点。最后一行是要查询的两个节点,计算出这两个节点的最近公共祖先
Output
对于每组测试输出一行,输出它们的最近公共祖先的编号。
分析:lca
代码:
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<queue>
using namespace std;
#define maxn 10005
int n,m,s;
int cnt,head[maxn],depth[maxn],p[maxn][25],fat[500005];
struct node{
int nxt,to;
}e[maxn];
void add(int x,int y){
e[++cnt].nxt=head[x];
head[x]=cnt;
e[cnt].to=y;
fat[y]=x;
}
void pre(int u,int fa){
depth[u]=depth[fa]+1;
p[u][0]=fa;
for(int i=1;1<<i<=depth[u];i++)p[u][i]=p[p[u][i-1]][i-1];
for(int i=head[u];i;i=e[i].nxt){
int v=e[i].to;
if(v!=fa)pre(v,u);
}
}
int lca(int a,int b){
if(depth[a]>depth[b])swap(a,b);
for(int i=20;i>=0;i--){
if(depth[a]<=depth[b]-(1<<i))b=p[b][i];
}
if(a==b)return a;
for(int i=20;i>=0;i--){
if(p[a][i]==p[b][i])continue;
else a=p[a][i],b=p[b][i];
}
return p[a][0];
}
int main(){
int t;scanf("%d",&t);
while(t--){
memset(head,0,sizeof(head));
memset(depth,0,sizeof(depth));
memset(p,0,sizeof(p));
memset(fat,0,sizeof(fat));
memset(e,0,sizeof(e));
cnt=0;
scanf("%d",&n);
for(int i=1;i<n;i++){
int x,y;scanf("%d%d",&x,&y);
add(x,y);
}
for(int i=1;i<=n;i++){
if(!fat[i]){
s=i;
break;
}
}
pre(s,0);
int a,b;scanf("%d%d",&a,&b);
printf("%d\n",lca(a,b));
}
return 0;
}
T3 P4281
题目描述
欢乐岛上有个非常好玩的游戏,叫做“紧急集合”。在岛上分散有 nnn 个等待点,有 n−1n-1n−1 条道路连接着它们,每一条道路都连接某两个等待点,且通过这些道路可以走遍所有的等待点,通过道路从一个点到另一个点要花费一个游戏币。
参加游戏的人三人一组,开始的时候,所有人员均任意分散在各个等待点上(每个点同时允许多个人等待),每个人均带有足够多的游戏币(用于支付使用道路的花费)、地图(标明等待点之间道路连接的情况)以及对话机(用于和同组的成员联系)。当集合号吹响后,每组成员之间迅速联系,了解到自己组所有成员所在的等待点后,迅速在 nnn 个等待点中确定一个集结点,组内所有成员将在该集合点集合,集合所用花费最少的组将是游戏的赢家。
小可可和他的朋友邀请你一起参加这个游戏,由你来选择集合点,聪明的你能够完成这个任务,帮助小可可赢得游戏吗?
输入格式
第一行两个正整数 nnn 和 mmm,分别表示等待点的个数(等待点也从 111 到 nnn 进行编号)和获奖所需要完成集合的次数。随后 n−1n-1n−1 行,每行两个正整数 a,ba,ba,b,表示编号为 aaa 和编号为 bbb 的等待点之间有一条路。随后 mmm 行,每行用三个正整数 x,y,zx,y,zx,y,z,表示某次集合前小可可、小可可的朋友以及你所在等待点的编号。
输出格式
输出共 mmm 行,每行两个用空格隔开的整数 p,cp,cp,c。其中第 iii 行表示第 iii 次集合点选择在编号为 ppp 的等待点,集合总共的花费是 ccc 个游戏币。
分析:
经分析,对每两个点求lca,三个点一定有其中两个lca相同,并在另一个lca上面,下面的lca一定是到三点路径并最小的,正确性显然。
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
#define maxn 500005
int n,m,s;
int cnt,head[maxn],depth[maxn],p[maxn][25],fat[maxn];
struct node{
int nxt,to;
}e[2*maxn];
void add(int x,int y){
e[++cnt].nxt=head[x];
head[x]=cnt;
e[cnt].to=y;
}
void pre(int u,int fa){
depth[u]=depth[fa]+1;
fat[u]=fa;
p[u][0]=fa;
for(int i=1;1<<i<=depth[u];i++)p[u][i]=p[p[u][i-1]][i-1];
for(int i=head[u];i;i=e[i].nxt){
int v=e[i].to;
if(v!=fa)pre(v,u);
}
}
int lca(int a,int b){
if(depth[a]>depth[b])swap(a,b);
for(int i=20;i>=0;i--){
if(depth[a]<=depth[p[b][i]])b=p[b][i];//printf("$$$$%d %d\n",i,b);
}
//printf("%d %d\n",a,b);
if(a==b)return a;
for(int i=20;i>=0;i--){
if(p[a][i]==p[b][i])continue;
else a=p[a][i],b=p[b][i];
}
return p[a][0];
}
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<n;i++){
int a,b;scanf("%d%d",&a,&b);
add(a,b);add(b,a);
}
pre(1,0);
//printf("sidjhsdl%d\n",depth[0]);
//for(int i=1;i<=n;i++){
// printf("%d",depth[i]);
// }
for(int i=1;i<=m;i++){
int x,y,z;
scanf("%d%d%d",&x,&y,&z);
int aa=lca(x,y);
int bb=lca(x,z);
int cc=lca(y,z);
// printf("%d %d %d\n",aa,bb,cc);
int t;
if(aa==bb)t=cc;
if(aa==cc)t=bb;
if(bb==cc)t=aa;
printf("%d %d\n",t,depth[x]+depth[y]+depth[z]-depth[aa]-depth[bb]-depth[cc]);
}
return 0;
}
0921 LCA练习的更多相关文章
- BZOJ 3083: 遥远的国度 [树链剖分 DFS序 LCA]
3083: 遥远的国度 Time Limit: 10 Sec Memory Limit: 1280 MBSubmit: 3127 Solved: 795[Submit][Status][Discu ...
- BZOJ 3626: [LNOI2014]LCA [树链剖分 离线|主席树]
3626: [LNOI2014]LCA Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 2050 Solved: 817[Submit][Status ...
- [bzoj3123][sdoi2013森林] (树上主席树+lca+并查集启发式合并+暴力重构森林)
Description Input 第一行包含一个正整数testcase,表示当前测试数据的测试点编号.保证1≤testcase≤20. 第二行包含三个整数N,M,T,分别表示节点数.初始边数.操作数 ...
- [bzoj2588][count on a tree] (主席树+lca)
Description 给定一棵N个节点的树,每个点有一个权值,对于M个询问(u,v,k),你需要回答u xor lastans和v这两个节点间第K小的点权.其中lastans是上一个询问的答案,初始 ...
- [板子]倍增LCA
倍增LCA板子,没有压行,可读性应该还可以.转载请随意. #include <cstdio> #include <cstring> #include <algorithm ...
- poj3417 LCA + 树形dp
Network Time Limit: 2000MS Memory Limit: 65536K Total Submissions: 4478 Accepted: 1292 Descripti ...
- [bzoj3626][LNOI2014]LCA
Description 给出一个$n$个节点的有根树(编号为$0$到$n-1$,根节点为$0$). 一个点的深度定义为这个节点到根的距离$+1$. 设$dep[i]$表示点$i$的深度,$lca(i, ...
- (RMQ版)LCA注意要点
inline int lca(int x,int y){ if(x>y) swap(x,y); ]][x]]<h[rmq[log[y-x+]][y-near[y-x+]+]])? rmq[ ...
- bzoj3631: [JLOI2014]松鼠的新家(LCA+差分)
题目大意:一棵树,以一定顺序走完n个点,求每个点经过多少遍 可以树链剖分,也可以直接在树上做差分序列的标记 后者打起来更舒适一点.. 具体实现: 先求x,y的lca,且dep[x]<dep[y] ...
随机推荐
- Java自学-图形界面 Swing中的线程
Swing中的线程 步骤 1 : 三种线程 在Swing程序的开发中,需要建立3种线程的概念 初始化线程 初始化线程用于创建各种容器,组件并显示他们,一旦创建并显示,初始化线程的任务就结束了. 事件调 ...
- Labview学习之路(四)公式和公式节点
在labview里边,有公式和公式节点两个控件都可以实现表达复杂表达式的功能 公式 位置: 程序框图---编程---Express---算数与比较---公式 用法: 点开后是这个样子 可以任意添加输出 ...
- docker快速搭建php7.2-nginx开发环境
1.输入命令: docker search -s 100 php 搜索出下面图中列表,选择webdevops/php-nginx. 2.通过docker拉取webdevops/php-nginx镜像, ...
- Unity可视化数据:创建图表
本文由Aoi翻译,转载请注明出处.文章来自于catlikecoding,原文作者介绍了Unity制作图表.可视化数据的方法.更多的名词解释内容,请点击末尾的“原文链接”查看. 介绍 这个教程里,我 ...
- Gama Space 和 Linear Space 学习
可以参考: 1.http://blog.csdn.net/ngrandmarch/article/details/46407017 2.http://blog.csdn.net/candycat199 ...
- 《神经网络的梯度推导与代码验证》之vanilla RNN前向和反向传播的代码验证
在<神经网络的梯度推导与代码验证>之vanilla RNN的前向传播和反向梯度推导中,我们学习了vanilla RNN的前向传播和反向梯度求导,但知识仍停留在纸面.本篇章将基于深度学习框架 ...
- 初探nmap
nmap 也就是Network Mapper用来扫描电脑开发的端口 主要功能: 探测主机在线情况 扫描主机开发端口和对应的大概服务命令: nmap 127.0.0.1 查看该主机开放的端口和端.端口类 ...
- vue父子组件状态同步的最佳方式
哈喽!大家好!我是木瓜太香,一位老牌儿前端工程师,平时我们在使用 vue 开发的时候,可能会遇到需要父组件与子组件某个状态需要同步的情况,通常这个是因为我们封装组件的时候有一个相同的状态外面要用,里面 ...
- leetcode刷题-82.删除排序链表中的重复元素 II
题目 给定一个排序链表,删除所有含有重复数字的节点,只保留原始链表中 没有重复出现 的数字. 示例 1: 输入: 1->2->3->3->4->4->5输出: 1- ...
- leetcode刷题-79单词搜索
题目 给定一个二维网格和一个单词,找出该单词是否存在于网格中. 单词必须按照字母顺序,通过相邻的单元格内的字母构成,其中“相邻”单元格是那些水平相邻或垂直相邻的单元格.同一个单元格内的字母不允许被重复 ...