倍增 LCA
以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的更多相关文章
- [板子]倍增LCA
倍增LCA板子,没有压行,可读性应该还可以.转载请随意. #include <cstdio> #include <cstring> #include <algorithm ...
- 洛谷P3128 [USACO15DEC]最大流Max Flow [倍增LCA]
题目描述 Farmer John has installed a new system of pipes to transport milk between the stalls in his b ...
- Gym100685G Gadget Hackwrench(倍增LCA)
题目大概说一棵边有方向的树,q个询问,每次询问结点u是否能走到v. 倍增LCA搞即可: 除了par[k][u]表示u结点往上走2k步到达的结点, 再加上upp[k][u]表示u结点往上走2k步经过边的 ...
- Codeforces 418d Big Problems for Organizers [树形dp][倍增lca]
题意: 给你一棵有n个节点的树,树的边权都是1. 有m次询问,每次询问输出树上所有节点离其较近结点距离的最大值. 思路: 1.首先是按照常规树形dp的思路维护一个子树节点中距离该点的最大值son_di ...
- hdu 4674 Trip Advisor(缩点+倍增lca)
花了一天半的时间,才把这道题ac= = 确实是道好题,好久没敲这么长的code了,尤其是最后的判定,各种销魂啊~ 题目中给出的条件最值得关注的就是:每个点最多只能在一个环内->原图是由一个个边连 ...
- Tsinsen A1505. 树(张闻涛) 倍增LCA,可持久化线段树,DFS序
题目:http://www.tsinsen.com/A1505 A1505. 树(张闻涛) 时间限制:1.0s 内存限制:512.0MB 总提交次数:196 AC次数:65 平均分: ...
- codevs 1036 商务旅行 (倍增LCA)
/* 在我还不知道LCA之前 暴力跑的SPFA 70分 三个点TLE */ #include<iostream> #include<cstdio> #include<cs ...
- hdu 2586 How far away ?倍增LCA
hdu 2586 How far away ?倍增LCA 题目链接 http://acm.hdu.edu.cn/showproblem.php?pid=2586 思路: 针对询问次数多的时候,采取倍增 ...
- 洛谷P4180 [Beijing2010组队]次小生成树Tree(最小生成树,LCT,主席树,倍增LCA,倍增,树链剖分)
洛谷题目传送门 %%%TPLY巨佬和ysner巨佬%%% 他们的题解 思路分析 具体思路都在各位巨佬的题解中.这题做法挺多的,我就不对每个都详细讲了,泛泛而谈吧. 大多数算法都要用kruskal把最小 ...
- 洛谷P2633 Count on a tree(主席树,倍增LCA)
洛谷题目传送门 题目大意 就是给你一棵树,每个点都有点权,每次任意询问两点间路径上点权第k小的值(强制在线). 思路分析 第k小......又是主席树了.但这次变成树了,无法直接维护前缀和. 又是树上 ...
随机推荐
- 【转载】高性能IO设计 & Java NIO & 同步/异步 阻塞/非阻塞 Reactor/Proactor
开始准备看Java NIO的,这篇文章:http://xly1981.iteye.com/blog/1735862 里面提到了这篇文章 http://xmuzyq.iteye.com/blog/783 ...
- Android面试题整理【转载】
面试宝典(5) http://www.apkbus.com/android-115989-1-1.html 面试的几个回答技巧 http://blog.sina.com.cn/s/blog_ad ...
- Oracle查看表结构的几种方法
1,DESCRIBE 命令 使用方法如下: SQL> describe nchar_tst(nchar_tst为表名) 显示的结果如下: 名称 ...
- Kafka 消息存储及检索(作者:杜亦舒)
Kafka 消息存储及检索 原创 2016-02-29 杜亦舒 性能与架构 Kafka是一个分布式的消息队列系统,消息存储在集群服务器的硬盘Kafka中可以创建多个消息队列,称为topic,消息的生产 ...
- LTIB常用命令2
LTIB 编译配置选项 根据说明文档,ltib 可以通过以下的命令配置: * <verbatim># ./ltib</verbatim> 安装后第一次运行,采 ...
- iOS开发 判断用户是否开启了定位
- (BOOL)achiveUserLocationStart { CLAuthorizationStatus status = [CLLocationManager authorizationSta ...
- Jni碰到的一个异常
Java与C++都有String对象,而c没有,只有char类型,所以在向C传入String类型的时候,如何处理需要注意一点 jstring Java_com_skymaster_hs_test4_M ...
- 慎用GetOpenFileName
这两天发现了一个小问题,经过一上午的排查终于找到了问题的原因--Windows 7的API函数GetOpenFileName竟然有BUG! 请参考下面的MFC代码: CFileDialog dlg(T ...
- 【bzoj1027】合金
[bzoj1027]合金 分析 数形结合+计算几何+Floyd最小环. http://blog.csdn.net/popoqqq/article/details/40539273 虽然这样占大家的很不 ...
- 【MYSQL】update/delete/select语句中的子查询
update或delete语句里含有子查询时,子查询里的表不能在update或是delete语句中,如含有运行时会报错:但select语句里含有子查询时,子查询里的表可以在select语句中. 如:把 ...