LCA专题
标签(空格分隔): LCA
我的个人网站挂了,最近就先用这个来写博客吧。以后争取在这个网站写一些与OI无关的个人爱好的东西。
题目来源:code[VS]
倍增--在线算法
用 $f[i][j]$ 记录从 $i$ 向上跳 $2^j$ 次会跳到的位置。需 $O(nlog(n))$ 的预处理与 $O(mlog(n))$ 的查询。具体如下:
//code[VS] P1036 LCA
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
struct Edge
{
int from,to,next;
bool access;
Edge(int form=0,int to=0,int next=0,bool access=true):from(from),to(to),next(next),access(access) {}
}e[60100];
int depth[30100],f[30100][25],v[25],pre[30100];
int n;
int c[30100];
void bfs(int s)
{
c[1] = s; depth[s] = 1;
int head = 1,tail = 1;
while (head<=tail)
{
int x = c[head++];
int v = pre[x];
while (v)
{
if (e[v].access)
{
depth[e[v].to] = depth[x] + 1;
c[++tail] = e[v].to;
f[e[v].to][0] = x;
e[v^1].access = false;
}
v = e[v].next;
}
}
}
void prepare()
{
v[0] = 1;
for (int j = 1; j<=20; j++)
for (int i = 1; i<=n; i++)
{
f[i][j] = f[f[i][j-1]][j-1];
v[j] = 2*v[j-1];
}
}
int LCA(int x,int y)
{
int ans=0;
if (depth[x] < depth[y]) swap(x,y);
for (int i = 20;depth[x]>depth[y];i--)
if (depth[f[x][i]] >= depth[y])
{
ans += v[i];
x = f[x][i];
}
if (x==y) return ans;
for (int i = 20; i>=0; i--)
if (f[x][i] != f[y][i])
{
x = f[x][i];
y = f[y][i];
ans += v[i]*2;
}
ans += 2;
return ans;
}
int main()
{
memset(pre,0,sizeof(pre));
scanf("%d",&n);
for (int i = 1; i<n; i++)
{
int x,y;
scanf("%d%d",&x,&y);
e[2*i] = Edge(x,y,pre[x],true);
pre[x] = 2*i;
e[2*i+1] = Edge(y,x,pre[y],true);
pre[y] = 2*i+1;
}
bfs(1);
prepare();
int m;
scanf("%d",&m);
int x,y=1,ans=0;
for (int i = 1; i<=m; i++)
{
x = y;
scanf("%d",&y);
ans += LCA(x,y);
}
printf("%d",ans);
}
Tarjan--离线算法
对于这么一个玄学的算法,我不想说太多。。。用并查集进行维护,可以证明,每当搜到 $x$ 时,与之对应的 $y$ 所在集合的祖先一定为这两点的LCA。
//code[VS] P1036 LCA
#include <cstdio>
#include <cstring>
struct Edge
{
int from,to,next;
bool access;
Edge(int from=0,int to=0,int next=0,bool access=true):from(from),to(to),next(next),access(access) {}
}e[60100];
struct Query
{
int point,next;
Query(int point=0,int next=0):point(point),next(next) {}
}q[60100];
//fa[i]记录i的父亲,f[i]记录i指向的第一条边,fq[i]记录i指向的第一个查询
int fa[30100],f[30100],fq[30100],depth[30100];
int ans=0; //记录答案
bool b[30100];
int c[30100];
void bfs(int s) //通过广搜计算出深度与边的方向
{
c[1] = s; depth[s] = 1;
int head = 1,tail = 1;
while (head<=tail)
{
int x = c[head++];
int v = f[x];
while (v)
{
if (e[v].access)
{
e[v^1].access = false; //将该边的反向边设为false
depth[e[v].to] = depth[x] + 1;
c[++tail] = e[v].to;
}
v = e[v].next;
}
}
}
int find(int x)
{
return x==fa[x]?x:fa[x]=find(fa[x]);
}
void Union(int x,int y)
{
int fy = find(y);
fa[fy] = x;
}
void Tarjan_LCA(int x)
{
fa[x] = x; //以x创建一个集合
int v = f[x];
while (v) //循环x的临边
{
if (e[v].access) //如果该边为正方向(即指向儿子)
{
Tarjan_LCA(e[v].to);
Union(x,e[v].to); //将x的子树与x合并
}
v = e[v].next;
}
b[x] = true; //设置该点已走过(必须在处理完儿子后设置,否则会有重复计算)
v = fq[x];
while (v) //处理关于x点的查询
{
if (b[q[v].point]) //如果另一点已走过 花费=a点深度+b点深度-2*LCA(a,b)的深度
ans = ans + ( depth[x] + depth[q[v].point] - 2*depth[find(q[v].point)] );
v = q[v].next;
}
}
int main()
{
memset(b,false,sizeof(b));
memset(f,0,sizeof(f));
memset(fq,0,sizeof(fq));
int n;
scanf("%d",&n);
for (int i = 1; i<n; i++)
{
int x,y;
scanf("%d%d",&x,&y);
e[2*i] = Edge(x,y,f[x],true);
f[x] = 2*i;
e[2*i+1] = Edge(y,x,f[y],true);
f[y] = 2*i+1;
}
int m;
scanf("%d",&m);
int x,y=1;
for (int i = 1; i<=m; i++) //因为不知先查询到哪个点所以要存储双向变
{
x = y;
scanf("%d",&y);
q[i*2-1] = Query(y,fq[x]);
fq[x] = 2*i-1;
q[2*i] = Query(x,fq[y]);
fq[y] = 2*i;
}
bfs(1);
Tarjan_LCA(1);
printf("%d",ans);
}
LCA专题的更多相关文章
- 在线倍增法求LCA专题
1.cojs 186. [USACO Oct08] 牧场旅行 ★★ 输入文件:pwalk.in 输出文件:pwalk.out 简单对比时间限制:1 s 内存限制:128 MB n个被自 ...
- HDU 2586——How far away ?
Time limit 1000 ms Memory limit 32768 kB Description There are n houses in the village and some bidi ...
- 专题训练之LCA
推荐几个博客:https://www.cnblogs.com/JVxie/p/4854719.html Tarjan离线算法的基本思路及其算法实现 https://blog.csdn.net/shah ...
- LCA(最近公共祖先)专题(不定期更新)
Tarjan(离线)算法 思路: 1.任选一个点为根节点,从根节点开始. 2.遍历该点u所有子节点v,并标记这些子节点v已被访问过. 3.若是v还有子节点,返回2,否则下一步. 4.合并v到u上. 5 ...
- bryce1010专题训练——LCA
1.Targan算法(离线) http://poj.org/problem?id=1470 /*伪代码 Tarjan(u)//marge和find为并查集合并函数和查找函数 { for each(u, ...
- poj3728 倍增法lca 好题!
lca的好题!网上用st表和离线解的比较多,用树上倍增也是可以做的 不知道错在哪里,等刷完了这个专题再回来看 题解链接https://blog.csdn.net/Sd_Invol/article/de ...
- SPOJ 10628. Count on a tree (树上第k大,LCA+主席树)
10628. Count on a tree Problem code: COT You are given a tree with N nodes.The tree nodes are number ...
- POJ 1330 Nearest Common Ancestors (LCA,倍增算法,在线算法)
/* *********************************************** Author :kuangbin Created Time :2013-9-5 9:45:17 F ...
- POJ 1470 Closest Common Ancestors (LCA,离线Tarjan算法)
Closest Common Ancestors Time Limit: 2000MS Memory Limit: 10000K Total Submissions: 13372 Accept ...
随机推荐
- canvas基础2--绘制图形
栅格 绘制矩形 不同于SVG,HTML中的元素canvas只支持一种原生的图形绘制:矩形.所有其他的图形的绘制都至少需要生成一条路径.不过,我们拥有众多路径生成的方法让复杂图形的绘制成为了可能. 首先 ...
- 关于在windows环境下配置xampp多站点问题
前言 由于开发要求,最近开始了php开发,于是就找到了xampp,wamp等集成环境,关于在windows下的xampp和wamp的配置,我过两天在写两篇分别阐述一下,下面就遇到的多站点的配置问题讲一 ...
- js里正则表达式详解
详细内容请点击 正则表达式中的特殊字符 字符 含意 \ 做为转意,即通常在"\"后面的字符不按原来意义解释,如/b/匹配字符"b",当b前面加了反斜杆后/\b/ ...
- 【CSS3】---last-of-type选择器+nth-last-of-type(n)选择器
last-of-type选择器 “:last-of-type”选择器和“:first-of-type”选择器功能是一样的,不同的是他选择是父元素下的某个类型的最后一个子元素. 示例演示 通过“:las ...
- Linq 合并数据并相加
有几条数据是这样的 Person 123 456 789 Person 321 654 987 想合并成 Person 444 1 ...
- IIS Session问题解决
Windows Server 2008 +IIS +ASP.net +SQLServer2008搭建的内部WEB系统. 发现用户Session总是不知不觉就自行遗失,原因就是 IIS的不稳定性将导致S ...
- asp.net 之 GC (垃圾回收机制)
今天抽时间好好整理了下GC相关知识,看了CSDN和博客园的几篇文章,有了一定的简单了解,决定根据个人理解整合一份随笔写下来,望诸位指教. 一:基础问题 1.首先需要知道了解什么是GC? GC如其名,就 ...
- Part 92 Significance of Thread Join and Thread IsAlive functions
Thread.Join & Thread.IsAlive functions Join blocks the current thread and makes it wait until th ...
- 发布ASP.NET网站到IIS
1. 在Web项目中点击发布网站,如图1所示 图1 2. 选择要发布的路径——>“确定”,如果项目显示发布成功就可以了.如图2所示 图2 3. 打 ...
- Windows删除大文件
Temp是目录 或者是 文件很大很大很大很大 cmd rd /s /q Temp