树上倍增 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开始只 ...
随机推荐
- 07 归档模式 Active redo log丢失或损坏的恢复
环境同上一篇 模拟处于active状态的redo log损坏 sesion 1 SYS@ orcl >/ GROUP# THREAD# SEQUENCE# BYTES BLOCKSIZE MEM ...
- MVC 源码系列之路由(一)
路由系统 注释:这部分的源码是通过Refector查看UrlRoutingModule的源码编写,这部分的代码没有写到MVC中,却是MVC的入口. 简单的说一下激活路由之前的一些操作.一开始是由MVC ...
- GARENA面试
约了2019年10月16日下午2点现场面 岗位:数据开发 下午2点准时到了公司,公司环境棒棒哒,hr小姐姐也是贴心,整个面试的过程真的棒棒哒. 在我所有的面试经历中,这个是体验感最棒的,其次是上中的面 ...
- 应用安全-Web安全-CSRF攻防整理
原理 - 登录受信任网站A,并在本地生成Cookie.在不登出A的情况下,访问危险网站B. #csrfdemo.php <?php $data = json_decode(file_get_co ...
- xmake v2.1.5版本新特性介绍
2.1.5版本现已进入收尾阶段,此版本加入了一大波新特性,目前正在进行稳定性测试和修复,在这里,先来介绍下新版本中引入了哪些新特性和改进. 1. 提供类似cmake的find_*系列接口,实现各种查找 ...
- Console.Out 属性和 XmlDocument.Save 方法 (String)
Console.Out 属性 默认情况下,此属性设置为标准输出流. 此属性可以设置为另一个流SetOut方法. 请注意,调用Console.Out.WriteLine方法是等效于调用相应WriteLi ...
- Python学习-第二天-字符串和常用数据结构
Python学习-第二天-字符串和常用数据结构 字符串的基本操作 def main(): str1 = 'hello, world!' # 通过len函数计算字符串的长度 print(len(str1 ...
- Excel VBA批量处理寸照名字(类模块加FSO版)
需求:因为处理学生学籍照片,从照相馆拿回来的寸照是按班级整理好,文件名是相机编号的文件.那么处理的话,是这么一个思路,通过Excel表格打印出各班A4照片列表,让学生自行填上照片对应姓名.表格收回来后 ...
- SpringMVC Controller单例和多例(转)
首先上测试代码 import org.springframework.context.annotation.Scope; import org.springframework.stereotype.C ...
- 什么是python??
python 是一门非常简单易学好用,同时功能强大的编程语言,具有丰富和强大的库,开发效率特别高.它常被昵称为胶水语言,能够把用其他语言制作的各种模块(尤其是C/C++)很轻松地联结在一起. pyth ...