以NOIP2013提高组day1 最后一道题为例来学的倍增和lca。其实这套题早就做过了,倍增和lca也学过,只不过当时没有理解清楚,所以今天再次学了一遍,虽然没有时间编程序了,但是先把思路和做法在这里梳理一遍,下次来编。

  首先,倍增。(树上倍增)

  f[i][j]表示在 j 节点向上跳2^ i 步后的节点。由2^ i =2^( i-1)+2^(i-1)可以得到递推式:f[i][j]=f[i-1][f[i-1][j]]。解释:从j节点向上跳2^ i 就相当于从j节点向上先跳2^(i-1)步到得节点,再从这个节点向上跳2^(i-1)步所到的点。

  所以得到:

 void bz()//倍增
{
for(int i=;i<=;i++)//i根据题意(深度)调大小
for(int j=;j<=n;j++)
fa[i][j]=fa[i-][fa[i-][j]];
}

  然后就是找lca(最近公共祖先)

  在这之前,首先要明确这两个点在树上的深度,先将较深的点向上跳到与另一点一样高(需要两点的深度差dh),然后再一起向上跳到最近公共祖先。怎么才能使两个点在同一深度呢?有两种方法,这里讲二进制的方法。深度差可以表示为二进制形式,如当dh=5时,为101,即这个点要在为1 的地方跳,先跳2^0步到一个节点,再从这个节点向上跳2^2步。可以用 if (1<< i & dh) 判断,当不等于0时,说明dh在第 i 位为1 ,需要跳,等于0时不需要跳就不管,每次更新跳到位置。

for(int i=;i<=;i++)//使两个点深度相同
{
if(<<i&dh)//位运算
{
// t1=min(t1,minax[i][s]);
s=fa[i][s];
}
}

  然后就是两个点一起向上跳到公共祖先,只需判断他们跳到的点是不是相同就可以了,因为如果超出了最近公共祖先那么他们跳到的节点就一定是同一节点,这时i 不可取,将 i 倒序循环,这样如果超过lca就会跳较少的步数到下面一点来判断是不是lca,如果这个时候又跳得太小了,那么更新现在跳到的节点,i 继续减小,从这个节点继续向上跳,重复上面的判断,由于跳的步数越来越少,越来越接近lca,那么最后一次一定是最接近lca的,这时,一定是跳两步多了,跳一步少了,所以刚好在lca下一个节点处,再加上1 即可。

 int lca(int s,int v)//找最近公共祖先,并求出最小值
{
int t1=INF,t2=INF;//两边子树最小值
if(F(s)!=F(v))return -;//判断是否连通
if(depth[v]>depth[s])//保证s在v下面
swap(s,v);
int dh=depth[s]-depth[v];
for(int i=;i<=;i++)//使两个点深度相同
{
if(<<i&dh)//位运算
{
t1=min(t1,minax[i][s]);
s=fa[i][s];
} }
if (s==v) return t1; //判断是否已经满足
for(int i=;i>=;i--)
{
if(fa[i][s]!=fa[i][v])
{
t1=min(t1,minax[i][s]);
t2=min(t2,minax[i][v]);
s=fa[i][s];
v=fa[i][v];
}
}
//此时两点都在最近公共祖先的下面,只需再向上走一步
t1=min(t1,minax[][s]);
t2=min(t2,minax[][v]);
return min(t1,t2);
}

  下来自己写一遍。。。谢谢anantheparty的博客。

  2016 10 09

  今天把货车运输这道题A了。

 #include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<queue>
#define maxn 10005
#define inf 100005
#define INF 12345678
using namespace std;
int n,m,q,fat[maxn],deth[maxn];
int tot,he[maxn],ne[inf],to[inf],w[inf];
int mimax[][maxn],f[][maxn];
bool notin[inf],flag[maxn];//notin[inf] not notin[maxn] RE
struct pp{
int x,y,v;
};
pp road[inf];
const int comp(const pp&a,const pp&b )
{
return a.v>b.v;
}
void add(int a,int b,int c)
{
tot++;to[tot]=b;ne[tot]=he[a];w[tot]=c;he[a]=tot;
}
int find(int a)
{
if (fat[a]!=a) return fat[a]=find(fat[a]);
return fat[a];
}
void kruskal()
{
for (int i=;i<=n;i++)
fat[i]=i;
for (int i=;i<=*m;i++)
{
int r1=find(road[i].x),r2=find(road[i].y);
if (r1!=r2) fat[r2]=r1;
else notin[i]=true;
}
}
void dfs(int u)
{
for (int i=he[u];i;i=ne[i])
if (!flag[to[i]]){
flag[to[i]]=;
deth[to[i]]=deth[u]+;
f[][to[i]]=u;
mimax[][to[i]]=w[i];//mimax[0][to[i]]
dfs(to[i]);
}
}
void bz()
{
for (int i=;i<=;i++)// i=1!!!
for (int j=;j<=n;j++)
{
f[i][j]=f[i-][f[i-][j]];
mimax[i][j]=min(mimax[i-][j],mimax[i-][f[i-][j]]);//mimax[i-1][j],f[i-1][j]
}
}
int lca(int a,int b)
{
int r1=INF,r2=INF;
if (find(a)!=find(b)) return -;
if (deth[a]<deth[b]) swap(a,b);
int d=deth[a]-deth[b];
for (int i=;i<=;i++)
{
if (<<i & d)
{
r1=min(mimax[i][a],r1);
a=f[i][a];
}
}
if (a==b) return r1;
for (int i=;i>=;i--)
{
if (f[i][a]!=f[i][b])
{
r1=min(mimax[i][a],r1);
r2=min(mimax[i][b],r2);
a=f[i][a];
b=f[i][b];
}
}
r1=min(r1,mimax[][a]);//!
r2=min(r2,mimax[][b]);//! 还有一步
return min(r1,r2);
}
int main()
{
// freopen("truck_lca.in","r",stdin);
cin>>n>>m;
for (int i=;i<=m;i++)
{
int a,b,c;
scanf("%d%d%d",&a,&b,&c);
road[i*-].x=a;road[i*].x=b;
road[i*-].y=b;road[i*].y=a;
road[i*-].v=c;road[i*].v=c;
}
sort(road+,road++*m,comp);
kruskal();
for (int i=;i<=*m;i++)
if (!notin[i]) {
add(road[i].x,road[i].y,road[i].v);
add(road[i].y,road[i].x,road[i].v);
}
for (int i=;i<=n;i++)
if (!deth[i]){
int r=find(i);
deth[r]=;
flag[r]=;
dfs(r);
}
bz();
cin>>q;
for (int i=;i<=q;i++)
{
int a,b;
scanf("%d%d",&a,&b);
printf("%d\n",lca(a,b));
}
return ;
}

  还是有很多小细节需要注意啊。。。

倍增 LCA的更多相关文章

  1. [板子]倍增LCA

    倍增LCA板子,没有压行,可读性应该还可以.转载请随意. #include <cstdio> #include <cstring> #include <algorithm ...

  2. 洛谷P3128 [USACO15DEC]最大流Max Flow [倍增LCA]

    题目描述 Farmer John has installed a new system of  pipes to transport milk between the  stalls in his b ...

  3. Gym100685G Gadget Hackwrench(倍增LCA)

    题目大概说一棵边有方向的树,q个询问,每次询问结点u是否能走到v. 倍增LCA搞即可: 除了par[k][u]表示u结点往上走2k步到达的结点, 再加上upp[k][u]表示u结点往上走2k步经过边的 ...

  4. Codeforces 418d Big Problems for Organizers [树形dp][倍增lca]

    题意: 给你一棵有n个节点的树,树的边权都是1. 有m次询问,每次询问输出树上所有节点离其较近结点距离的最大值. 思路: 1.首先是按照常规树形dp的思路维护一个子树节点中距离该点的最大值son_di ...

  5. hdu 4674 Trip Advisor(缩点+倍增lca)

    花了一天半的时间,才把这道题ac= = 确实是道好题,好久没敲这么长的code了,尤其是最后的判定,各种销魂啊~ 题目中给出的条件最值得关注的就是:每个点最多只能在一个环内->原图是由一个个边连 ...

  6. Tsinsen A1505. 树(张闻涛) 倍增LCA,可持久化线段树,DFS序

    题目:http://www.tsinsen.com/A1505 A1505. 树(张闻涛) 时间限制:1.0s   内存限制:512.0MB    总提交次数:196   AC次数:65   平均分: ...

  7. codevs 1036 商务旅行 (倍增LCA)

    /* 在我还不知道LCA之前 暴力跑的SPFA 70分 三个点TLE */ #include<iostream> #include<cstdio> #include<cs ...

  8. hdu 2586 How far away ?倍增LCA

    hdu 2586 How far away ?倍增LCA 题目链接 http://acm.hdu.edu.cn/showproblem.php?pid=2586 思路: 针对询问次数多的时候,采取倍增 ...

  9. 洛谷P4180 [Beijing2010组队]次小生成树Tree(最小生成树,LCT,主席树,倍增LCA,倍增,树链剖分)

    洛谷题目传送门 %%%TPLY巨佬和ysner巨佬%%% 他们的题解 思路分析 具体思路都在各位巨佬的题解中.这题做法挺多的,我就不对每个都详细讲了,泛泛而谈吧. 大多数算法都要用kruskal把最小 ...

  10. 洛谷P2633 Count on a tree(主席树,倍增LCA)

    洛谷题目传送门 题目大意 就是给你一棵树,每个点都有点权,每次任意询问两点间路径上点权第k小的值(强制在线). 思路分析 第k小......又是主席树了.但这次变成树了,无法直接维护前缀和. 又是树上 ...

随机推荐

  1. Matlab中的persistent变量

    persistent, 用于定义persistent变量.persistent变量对于声明它的函数来说是局部的,但是当退出该函数时,该变量仍然保存在内存中,数值并不变.persistent变量与全局变 ...

  2. 在map中根据value获取key

    原文:http://blog.csdn.net/mexican_jacky/article/details/51789548 //根据map的value获取map的key private static ...

  3. mysql ERROR 1044 (42000): Access denied for user ''@'localhost' to database

    新安装的mysql密码是空的. ./mysql -u root -p use mysql SELECT `Host`,`User` FROM user; UPDATE user SET `Host` ...

  4. JS获得事件发出者

    因为ff下本身不支持srcElement而是支持target,你这里这么用也是为了兼容浏览器,但是event.srcElement.id这么写会从event.srcElement里找id属性,这样是默 ...

  5. unsigned char 无符号整形 减法运算

    对于一个字节来说: unsigned char :     0  ~  255              0000 0000  ~ 1111 1111 char :-128  ~  127       ...

  6. /dev/sda3: UNEXPECTED INCONSISTENCY; RUN fsck MANUALLY

    系统强制断电后,出现以下错误: /dev/sda3: UNEXPECTED INCONSISTENCY; RUN fsck MANUALLY 启动系统后在字符界面有两个选项,输入root密码进入维护模 ...

  7. git status 不可全信

    不要相信git status,除非在操作的过程中, 看git仓库和本地.git之间的差异 -比如我现在在github上某个分支下上传了某个文件,但我在本地git status显示的还是working ...

  8. grub4dos通用菜单及相关工具包

    grub4dos通用菜单及相关工具包 全套工具包(含PE.ISO,可根据需要替换删减):http://pan.baidu.com/s/1i4EjWod模板文件3.3M(不含PE.ISO):http:/ ...

  9. x+y = ((x&y)<<1) + (x^y) 证明

    法一:我们考虑x,y在二进制表示时候,按位相加其中第i位xi+yi = ((xi&yi)<<1) + (xi^yi)其中(xi&yi)<<1表示当xi和yi都是 ...

  10. Unity3D中目标相对自身的前后左右方位判断

    http://blog.csdn.net/cen616899547/article/details/38336185 在做rpg类游戏的过程中,经常遇到要判断周围怪物相对自身的方位   1.判断目标在 ...