树上倍增 x
树上倍增.
dfs序的做法:
思路:
//f[i][j]表示dfs序中序号为i到序号为j的点之间深度最小的点的编号
dfs序[]//存0-...(id)编号
节点[]//存dfs序中所经过的节点号
dep[]//存走过的点所对应的点的深度
i : ......
id[i] : (该点在节点编号中第一次出现的位置所对应的dfs序编号)
//ans表示求u节点到i节点的最短距离...
ans=f[id[u]][id[v]];
至于代码……额……没写
树上倍增还能够用来求LCA
其中f[i,j]表示i的第2^j祖先dfs预处理f[i,j]=f[f[i,j-1],j-1];
对于每一对x,y先将深度调成一样再枚举j逐一往上找,这两个过程都是log的
代码如下:
#include <iostream>
#include <cstdio>
#include <cmath>
//maybe my English is not very good using namespace std; const int M = 5e5 + ;
int n,m,s;
int num;
int deep[M],h[M];
bool vs[M];
int jumps[M][];
int p; struct A{
int next;
int to;
}t[M<<]; inline int read() //optimize
{
int x=,f=;char ch=getchar(); while(ch<''||ch>'')
{
if(ch=='-') f=-;
ch=getchar();
} while(ch>=''&&ch<='')
{
x=x*+ch-'';
ch=getchar();
} return x*f;
} void ADD(int x,int y) //connect the x and the y
{
num++;
t[num].to=y;
t[num].next=h[x];
h[x]=num;
} void Dfs(int u)
{
for(int i=h[u];i!=-;i=t[i].next)
{
int v=t[i].to; //u's next side
if(deep[v] == ) //if v is not visited
{
deep[v]=deep[u]+; //deep+1
jumps[v][]=u; //u is v's dad
Dfs(v); //continue Dfs
}
}
} void steps()
{
p=int(log(n)/log()+0.001); //find the biggest
for(int i=;i<=p;i++) //the Limit
for(int j=;j<=n;j++)
jumps[j][i]=jumps[jumps[j][i-]][i-];
//the j jump 2^i can get to the (first jump 2^(i-1),then jump 2^i-1 can get to)
//eh...I will speak in Chinese.
//because 倍增 is use 次方的形式 increase
} int LCA(int a,int b)
{
//We let the b's deep is small
if(deep[a]<deep[b]) swap(a,b);
for(int i=p;i>=;i--)
{//first let the a jump to the b's deep
if(deep[jumps[a][i]]>=deep[b])
a=jumps[a][i];
}
if(a == b) return b; //if the b is them's LCA , return b
for(int i=p;i>=;i--) //jump together
{
if(jumps[a][i]!=jumps[b][i])
a=jumps[a][i],b=jumps[b][i]; //update
}
return jumps[a][];
} int main()
{
//s is the root
n=read();m=read();s=read();
for(int i=;i<=n;i++) h[i]=-;
int x,y;
for(int i=;i<n;i++)
{
x=read();y=read();
//connect the x and the y
ADD(x,y);
ADD(y,x);
}
deep[s]=; //this is too important !!!
//if you don't think so ,"//" it.
//and then you will know
Dfs(s); //Dfs the root(s)
steps(); //find the steps
int a,b;
while(m--)
{
a=read();b=read();
printf("%d\n",LCA(a,b));
}
return ;
} 树上倍增英文版???
1
#include<iostream>
#include<cmath>
#include<algorithm>
#include<cstring>
#include<cstdio>
#include<stdio.h>
#include<vector>
#define maxn 500500
using namespace std;
///隶属邻接表
struct Edge{ //邻接表的结构体
int from,to;
}edges[*maxn]; //边要乘2,因为是无向图 ;
int first[maxn],next[*maxn]; //同理;
int read(){ //读入优化,可以照着这个模板来写,这个还算写的比较好看。
int re=;
char ch=getchar();
while (ch<'' || ch>'') ch=getchar();
while (ch>='' && ch<=''){
re=re*+ch-'';
ch=getchar();
}
return re;
}
///////////////////////////////////////////////
///全局变量
int n,m;
int root;
int height[maxn];
float log2n;
///////////////////////////////////////////////////////
///隶属LCA的全局变量
int f[maxn][];//
int have[maxn]; //have,有没有找过,这都是套路 。
void dfs(int u,int h){ //u代表点的标号,h代表高度。
int v;
height[u]=h;
for(int i=;i<=log2n;i++) {
if(h<=(<<i)) break; //由于i是从小到大计算的,故(1<<i)>=h 时可直接退出。请务必想清楚是<= 还是=。
f[u][i] = f[ f[u][i-] ][i-]; //动规计算。同样也是一切倍增算法的核心。
}
int k=first[u];
while(k!=-){
v=edges[k].to;
if(!have[v]) {
have[v]=;
f[v][]=u; //将要找的下一个点的父节点标为当前处理的节点u。
dfs(v,h+);
}
k=next[k];
}
}
int require_LCA(int a,int b){
int da=height[a],db=height[b];
//第一步,将a,b两点移到同样的高度,只动高度大的那个点而不动高度小的那个点。
if(da!=db) {
if(da<db){ //保证a的高度是大于b的高度的。
swap(a,b);
swap(da,db);
}
int d=da-db;
for(int i=;i<=log2n;i++)
if( (<<i) & d) a=f[a][i]; //这里的位运算可以减少代码量
//考虑到d是一个定值,而(1<<i)在二进制中只有第(i+1)位是1;
//那么d与(1<<i)如果某一位为1,那么表示可以向上移动,
//如果此时不移动,那么i增大了后就无法使height[a]==height[b]了
}
//第二步,找到某个位置i,在这个位置时,f[a][i]!=f[b][i],但再向上移动一步,a,b相同了
//从log2n开始从大到小枚举i,如果超过了a,b的高度,则令i继续减小
//如果没有超过a,b的高度,那么就判断移动了后会不会让a==b,
//是,则i继续减小,否则,令此时的a=f[a][i],b=f[b][i];
if(a==b) return b;
int i=;
for(i=log2n;i>=;i--) {
if(height[ f[a][i] ]<) continue;
if( f[a][i]==f[b][i] ) continue;
else a=f[a][i],b=f[b][i]; //顺便一提,在第二步任何地方没有break;
//我就是因为在这里写了一个break,然后找了我两个小时啊。
}
return f[a][];
}
/////////////////////////////////
///据说从主函数开始阅读是个好习惯。
int main(){
// freopen("in2.txt","r",stdin);
n=read();m=read();root=read();
memset(first,-,sizeof(first));
memset(next,-,sizeof(next));
int s,t;
int dsd=*(n-);
for(int i=;i<=dsd;i+=) {
s=read();t=read(); //读入优化。
edges[i].from=s;
edges[i].to=t;
edges[i+].from=t;
edges[i+].to=s;
next[i]=first[s];
first[s]=i;
next[i+]=first[t];
first[t]=i+;
}
// 以上是邻接表,在此不再赘述。
log2n=log(n)/log()+; //C++计算log是自然对数,我们要用的以2为底的对数,故要除以log(2);
//对无理数加上1或是0.5是个好习惯,可以减小误差;
memset(have,,sizeof(have));
memset(height,,sizeof(height));
memset(f,-,sizeof(f));
have[root]=; //fa[][]和height[]要在dfs理进行计算,不然根本找不到某个非根节点的父亲是谁;
dfs(root,);
for(int i=;i<=n;i++){
for(int j=;j<=log2n;j++) {
if(height[i] <=(<<j) ) break;
}
}
for(int i=;i<m;i++) { //应对要求进行求解。
s=read();t=read();
int y=require_LCA(s,t);
printf("%d\n",y);
}
return ;
}
2
End.
树上倍增 x的更多相关文章
- Codevs 2370 小机房的树 LCA 树上倍增
题目描述 Description 小机房有棵焕狗种的树,树上有N个节点,节点标号为0到N-1,有两只虫子名叫飘狗和大吉狗,分居在两个不同的节点上.有一天,他们想爬到一个节点上去搞基,但是作为两只虫子, ...
- NOIP2013 货车运输 (最大生成树+树上倍增LCA)
死磕一道题,中间发现倍增还是掌握的不熟 ,而且深刻理解:SB错误毁一生,憋了近2个小时才调对,不过还好一遍AC省了更多的事,不然我一定会疯掉的... 3287 货车运输 2013年NOIP全国联赛提高 ...
- HDU 4822 Tri-war(LCA树上倍增)(2013 Asia Regional Changchun)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4822 Problem Description Three countries, Red, Yellow ...
- [NOIP2013/Codevs3287]货车运输-最小[大]生成树-树上倍增
Problem 树上倍增 题目大意 给出一个图,给出若干个点对u,v,求u,v的一条路径,该路径上最小的边权值最大. Solution 看到这个题第一反应是图论.. 然而,任意路径最小的边权值最大,如 ...
- 树上倍增求LCA及例题
先瞎扯几句 树上倍增的经典应用是求两个节点的LCA 当然它的作用不仅限于求LCA,还可以维护节点的很多信息 求LCA的方法除了倍增之外,还有树链剖分.离线tarjan ,这两种日后再讲(众人:其实是你 ...
- [树上倍增+二分答案][NOIP2012]运输计划
题目背景 公元 2044 年,人类进入了宇宙纪元. 题目描述 公元 2044 年,人类进入了宇宙纪元 L 国有 nn 个星球,还有 n-1n−1 条双向航道,每条航道建立在两个星球之间,这 n-1n− ...
- 两种lca的求法:树上倍增,tarjan
第一种:树上倍增 f[x,k]表示x的2^k辈祖先,即x向根结点走2^k步达到的结点. 初始条件:f[x][0]=fa[x] 递推式:f[x][k]=f[ f[x][k-1] ][k-1] 一次bfs ...
- 【NOIP2013/Codevs3287】货车运输-最小生成树(大)-树上倍增
https://www.luogu.org/problemnew/show/P1967 由题可知,我们走的路的边应尽可能大,所以通过kruscal建最大生成树的图,再树上倍增,注意可能有多棵树; #i ...
- LCA树上倍增
LCA就是最近公共祖先,比如 节点10和11的LCA就是8,9和3的LCA就是3. 我们这里讲一下用树上倍增来求LCA. 大家都可以写出暴力解法,两个节点依次一步一步往上爬,直到爬到了相同的一个节点. ...
- BZOJ3545&3551[ONTAK2010]Peaks——kruskal重构树+主席树+dfs序+树上倍增
题目描述 在Bytemountains有N座山峰,每座山峰有他的高度h_i.有些山峰之间有双向道路相连,共M条路径,每条路径有一个困难值,这个值越大表示越难走,现在有Q组询问,每组询问询问从点v开始只 ...
随机推荐
- 阶段1 语言基础+高级_1-3-Java语言高级_06-File类与IO流_04 IO字节流_13_使用字节流读取中文的问题
编码格式右下角显示是UTF-8 前三个字节是你,后三个字节是好.一个汉字占用了三个字节 读一个字节让编程char类型 文件里面后面加上abc abc没有问题 所以java提供字符流.字符流一次读取一个 ...
- 阶段1 语言基础+高级_1-3-Java语言高级_04-集合_08 Map集合_7_HashMap存储自定义类型键值
自定义类型做key值.必须要重写hashCode和equals方法 创建pserson类 有name个age两个成员变量.重写toString方法 key有重复,会被新的value值替换掉. key值 ...
- [转载]OpenSSL中文手册之命令行详解(未完待续)
声明:OpenSSL之命令行详解是根据卢队长发布在https://blog.csdn.net/as3luyuan123/article/details/16105475的系列文章整理修改而成,我自己 ...
- lua 转换16进制字符串为10进制数值
lua 转换16进制字符串为10进制数值 > print(tonumber()) 利用tonumber函数,“16”表示“03FFACB”为16进制数.
- 浅谈数学上的矩阵——矩阵的乘法运算的概念及C++上的实现模板
首先让我们来谈一谈数学意义上的矩阵(在座各位也可以简单地将它理解为一个二维数组) 这样可以帮助我们理解矩阵加速及其运用的原理(矩阵加速是一个及其玄学的东西,所以请重点理解矩阵乘法) 这里给出一段严格 ...
- TensorFlow学习笔记7-深度前馈网络(多层感知机)
深度前馈网络(前馈神经网络,多层感知机) 神经网络基本概念 前馈神经网络在模型输出和模型本身之间没有反馈连接;前馈神经网络包含反馈连接时,称为循环神经网络. 前馈神经网络用有向无环图表示. 设三个函数 ...
- [Python3 练习] 004 水仙花数
题目:水仙花数 (1) 描述 水仙花数各位的数字的立方之和等于自身 如 153 为水仙花数,因为 153 = 1^3 + 5^3 + 3^3 (2) 要求 找到所有的三位数的水仙花数 (3) 程序 # ...
- Vue+axios+Node+express实现文件上传(用户头像上传)
Vue 页面的代码 <label for='my_file' class="theme-color"> <mu-icon left value="bac ...
- XE2再次安装JVCL
说再次安装,是因为我忘了自己之前写过的方法,装完之后感觉怪怪的,想看看别人是怎么装的,于是用google搜索了一下,才发现之前写过: http://www.cnblogs.com/findumars/ ...
- Java缓存Ehcache-Ehcache的Cache在SSM框架中的配置
需要在Spring配置文件中配置: <!-- 配置缓存管理器工厂 --> <bean id="cacheManager" class="org.spri ...