LCA算法倍增算法(洛谷3379模板题)
倍增(爬树)算法,刚刚学习的算法。对每一个点的父节点,就记录他的2k的父亲。
题目为http://www.luogu.org/problem/show?pid=3379
第一步先记录每一个节点的深度用一个深搜,顺便对每个节点的20赋初值为自己的上一个节点。
第二步通过第一步的初始化对每个节点的2k次进行赋值为fa[i][j]=fa[ fa[i][j-1] ][ j-1 ];自己的j-1次幂的父节点的i-1次就是就是自己的j次幂。
第三步对询问做出处理
1,先判断x,y的深度,如果x比y浅就换位置,让x为深的节点
2,让x上升到和y一样的高度
3,找到他们两个第一个相等的点,一直上升2k次,直到不相等了就让x和y等于他,输出的时候输出的值是fa[x][0]也就是他的上一个点,这是他们相等的点。
输入:N、M、S,分别表示树的结点个数、询问的个数和树根结点的序号。
接下来N-1行每行包含两个正整数x、y,表示x结点和y结点只见有一条直接连接的边(数据保证可以构成树)。
接下来M行每行包含两个正整数a、b,表示询问a结点和b结点的最近公共祖先。
输出包含M行,每行包含一个正整数,依次为每一个询问的结果。
#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
using namespace std;
#define MAX 500010
//=================================================
struct NODE{
int next,point;
NODE(){ next=; }
}edge[];
//=================================================
int N,M,S;
int link[MAX],edgenum=,fa[MAX][];
int deep[MAX];
//=================================================
void init();
void ADD(int ,int );
void DFS(int );
void find();
void pt();
int LCA(int x,int y);
//=================================================
int LCA(int x,int y)
{
if(deep[x]<deep[y])swap(x,y); //如果x比y浅,就让他们两个交换,让x为比较深的那个
for(int i=;i>=;i--){ //注意这里是倒叙,从大k到小k,如果x的k次幂比y深或等于y的深度了就让x等于过去,然后k还会减小
if( deep[ fa[x][i] ] >= deep[y] ) //这样x就可以慢慢逼近直到等于y的深度
x=fa[x][i]; //将x上升到跟y一样的高度上
}
if(x==y)return x;
for(int i=;i>=;i--){ //这里和上边一样,倒叙进行
if( fa[x][i]!=fa[y][i] ) //一只循环到x的0次和y的0次相等的时候,但是这个时候x不等于y也不是公共祖先
x=fa[x][i],y=fa[y][i]; //他们的公共祖先是x的0次幂或y的0次幂所以返回的值是fa[x][0];
}
return fa[x][];
}
//=================================================
void pt()
{
for(int i=;i<=M;i++){
int x,y;
scanf("%d%d*c",&x,&y);
printf("%d\n",LCA(x,y));
}
}
//=================================================
void find()
{
for(int i=;i<=;i++){
for(int j=;j<=N;j++){
fa[j][i]=fa[ fa[j][i-] ][i-]; //确定自己的所有倍增父节点
}
}
}
//=================================================
void DFS(int u)
{
for(int i=link[u];i!=;i=edge[i].next){
int v=edge[i].point;
if(deep[v]==){
deep[v]=deep[u]+; //下一个点的深度为这个点的深度加一
fa[v][]=u; //2的0次幂就是自己的父节点
DFS(v);
}
}
}
//=================================================
void ADD(int x,int y)
{
edgenum++;
edge[edgenum].point=y;
edge[edgenum].next=link[x];
link[x]=edgenum;
}
//=================================================
void init()
{
scanf("%d%d%d",&N,&M,&S);
for(int i=;i<N;i++){
int x,y;
scanf("%d%d*c",&x,&y);
ADD(x,y);
ADD(y,x);
}
}
//=================================================
int main()
{
init(); //初始化
deep[S]=;
DFS(S); //深搜找深度
find(); //找每个点的2k次父节点
pt(); //输入询问输出答案
return ;
}
LCA算法倍增算法(洛谷3379模板题)的更多相关文章
- 【后缀数组】洛谷P3809模板题
题目背景 这是一道模板题. 题目描述 读入一个长度为 n n n 的由大小写英文字母或数字组成的字符串,请把这个字符串的所有非空后缀按字典序从小到大排序,然后按顺序输出后缀的第一个字符在原串中的位置. ...
- 【AC自动机】洛谷三道模板题
[题目链接] https://www.luogu.org/problem/P3808 [题意] 给定n个模式串和1个文本串,求有多少个模式串在文本串里出现过. [题解] 不再介绍基础知识了,就是裸的模 ...
- 【最大流ISAP】洛谷P3376模板题
题目描述 如题,给出一个网络图,以及其源点和汇点,求出其网络最大流. 输入输出格式 输入格式: 第一行包含四个正整数N.M.S.T,分别表示点的个数.有向边的个数.源点序号.汇点序号. 接下来M行每行 ...
- 【后缀自动机】洛谷P3804模板题
题目描述 给定一个只包含小写字母的字符串SSS, 请你求出 SSS 的所有出现次数不为 111 的子串的出现次数乘上该子串长度的最大值. 输入输出格式 输入格式: 一行一个仅包含小写字母的字符串SSS ...
- 洛谷 3379 最近公共祖先(LCA 倍增)
洛谷 3379 最近公共祖先(LCA 倍增) 题意分析 裸的板子题,但是注意这题n上限50w,我用的边表,所以要开到100w才能过,一开始re了两发,发现这个问题了. 代码总览 #include &l ...
- 洛谷P3373 [模板]线段树 2(区间增减.乘 区间求和)
To 洛谷.3373 [模板]线段树2 题目描述 如题,已知一个数列,你需要进行下面两种操作: 1.将某区间每一个数加上x 2.将某区间每一个数乘上x 3.求出某区间每一个数的和 输入输出格式 输入格 ...
- 洛谷 P4148 简单题 KD-Tree 模板题
Code: //洛谷 P4148 简单题 KD-Tree 模板题 #include <cstdio> #include <algorithm> #include <cst ...
- 【noip】跟着洛谷刷noip题2
noip好难呀. 上一个感觉有点长了,重开一个. 36.Vigenère 密码 粘个Openjudge上的代码 #include<cstdio> #include<iostream& ...
- [洛谷P1707] 刷题比赛
洛谷题目连接:刷题比赛 题目背景 nodgd是一个喜欢写程序的同学,前不久洛谷OJ横空出世,nodgd同学当然第一时间来到洛谷OJ刷题.于是发生了一系列有趣的事情,他就打算用这些事情来出题恶心大家-- ...
随机推荐
- Oracle10g新特性——正则表达式 - 转
在进行查询时,有时候需要按照一定的特殊规则来查找某个字符串,比如,你可能需要查询第三位为5-8,最后四位为’8888’的所有电话.在9i之前,你可能需要写一个很复杂的条件:Select usernam ...
- Android开发之ProgressDialog在独立Thread线程中更新进度
简单的需求:在一个工作Thread中更新进度对话框ProgressDialog 遇到的问题: 1,创建需要Context,这个需要传进来 2,Thread中不能创建ProgressDialog,否则需 ...
- CentOS 6 安装 python 2.7 和 mod_wsgi 运行pyocr[tesseract]
最新版本的tesseract-ocr 3.0.4 需要运行于python2.7版本以上,因此需要升级系统中默认的2.6版本python及Mod_WSGI 1,下载安装Python-2.7.10 > ...
- Oracle数据库入门——初级系列教程
- Qt编写自定义控件一开关按钮
从2010年进入互联网+智能手机时代以来,各种各样的APP大行其道,手机上面的APP有很多流行的元素,开关按钮个人非常喜欢,手机QQ.360卫士.金山毒霸等,都有很多开关控制一些操作,在Qt widg ...
- MarkDown写blog(测试)
区块元素 段落和换行 一个 Markdown 段落是由一个或多个连续的文本行组成,它的前后要有一个以上的空行(空行的定义是显示上看起来像是空的,便会被视为空行.比方说,若某一行只包含空格和制表符,则该 ...
- [iOS]关于状态栏(UIStatusBar)的若干问题
版本: OS X 10.10.5 Xcode 6.4(6E35b) iOS >= 7 一.概述 状态栏(UIStatusBar)指iPhone/iPad/iPod屏幕顶部用于显示网络.时间和电量 ...
- 享元模式及C++实现
享元模式(flyweight) flyweight是轻量级的意思,中文这边翻译成享元,更容易让人理解一些. 享元模式是为了应对大量细粒度对象重复的问题.程序中存在大量细粒度的对象,每次要使用时都必须创 ...
- chrome 插件 vimium 像操作vim一样的操作浏览器
感谢潘德龙同学推荐的插件非常好用整理出来一些常用快捷键记下,顺便分享! x 关闭当前页 GW 跳出浏览器 J 展示左边页签 K展示右边页签 j向下滚动 k向上滚动 /搜索 ?打开帮助 r 刷新当前页 ...
- CentOS下安装JDK7 转载
转载地址:http://www.cnblogs.com/rilley/archive/2012/02/02/2335395.html CentOS下安装JDK7 下载地址:http://www.ora ...