午时刷题,难甚,遂小憩于桌上,惊醒,于梦中有所得,虽大声曰:吾已得tarjan之奥秘!

关于tarjan算法,其实就是一个递归加并查集的应用。

大致代码:

#include<bits/stdc++.h>
using namespace std;
int find(int x){
....
} void join(int x,int y)
{
....
}
void dfs(int x)
{
int len=v[x].size();
for(int i=; i<len; i++) //遍历x的子节点
{
dfs(v[x][i]); //继续往下推
join(v[x][i],x); //将x的所有子节点的祖先都设为x
}
vis[x] = true; //证明x走过了
for(int i=; i<=n; i++) //对每个x循环1~n
if(vis[i]&&g[x][i]) //如果i已经走过并且要求(x,i)
ans=find(i); //lca就是ans
}

由以上代码可以看出,tarjan实际上就是并查集与dfs的结合,其最核心的部分就是dfs那部分

只要理解了dfs()的内容,就能理解tarjan

而对于dfs函数,我们首先就会想到它的特性:不撞南墙不回头。

假如有一颗树,对其dfs,那么首先它会沿着一个分支一直到尽头(如图):

而当走到4这个点时,函数开始执行下列语句:

join(v[x][i],x);        //将x的所有子节点的祖先都设为x 
//而此时pre[4]=3;pre[3]=3;pre[2]=2;pre[1]=1;

再然后是:

 vis[x] = true;              //证明x走过了
for(int i=1; i<=n; i++) //对每个x循环1~n
if(vis[i]&&g[x][i]) //如果i已经走过并且要求(x,i)
ans=find(i); //lca就是ans
}
如果存在要求lca[x][i],先看i点是否走过,如果走过,那就只有一种可能(真相只有一个!真実はいつも一つ):

i,k必在两条不同分支上,并且交于某个点x,如果i已经走过了,那么,i所在的这条分支上所有的点都有明确的父子关系,即find(i)==x!
代码参上:
#pragma GCC optimize(2)
#include<stdio.h>
#include<string.h>
#include<vector>
#define M 1007
using namespace std;
int g[M][M],in[M],pre[M],cnt[M];
bool vis[M];
vector<int>v[M];
int n,m;
void init()
{
memset(g,,sizeof(g));
memset(in,,sizeof(in));
memset(cnt,,sizeof(cnt));
memset(vis,false,sizeof(vis));
for(int i=; i<=n; i++)
{
v[i].clear();
pre[i]=i;
}
}
int fond(int x)
{
return x==pre[x]?x:pre[x]=fond(pre[x]);
}
void join(int x,int y)
{
int xx=fond(x);
int yy=fond(y);
pre[xx]=yy;
}
void dfs(int x)
{
int len=v[x].size();
for(int i=; i<len; i++) //遍历x的子节点
{
dfs(v[x][i]); //继续往下推
join(v[x][i],x); //将x的所有子节点的祖先都设为x
}
vis[x] = true; //证明x走过了
for(int i=; i<=n; i++) //对每个x循环1~n
if(vis[i]&&g[x][i]) //如果i已经走过并且要求(x,i)
cnt[fond(i)]+=g[x][i]; //
}
int main()
{
while(scanf("%d",&n)!=EOF)
{
init();
int a,b,c,root;
for(int i=; i<=n; i++)
{
scanf("%d:(%d)",&a,&b);
while(b--)
{
scanf(" %d",&c);
v[a].push_back(c);
in[c]++;
}
}
scanf("%d",&m);
getchar();
while(m--)
{
scanf("(%d,%d)",&a,&b);
getchar();
g[a][b]++;
g[b][a]++;
}
for(int i=; i<=n; i++)
if(!in[i])
{
root=i;
break;
}
dfs(root);
for(int i=; i<=n; i++)
{
if(cnt[i])
printf("%d\n",i);
}
}
return ;
}
以上;

Closest Common Ancestors (Lca,tarjan)的更多相关文章

  1. poj 1470 Closest Common Ancestors LCA

    题目链接:http://poj.org/problem?id=1470 Write a program that takes as input a rooted tree and a list of ...

  2. POJ1470 Closest Common Ancestors 【Tarjan的LCA】

    非常裸的模版题,只是Tarjan要好好多拿出来玩味几次 非常有点巧妙呢,tarjan,大概就是当前结点和它儿子结点的羁绊 WA了俩小时,,,原因是,这个题是多数据的(还没告诉你T,用scanf!=EO ...

  3. POJ 1470 Closest Common Ancestors(LCA&RMQ)

    题意比较费劲:输入看起来很麻烦.处理括号冒号的时候是用%1s就可以.还有就是注意它有根节点...Q次查询 在线st算法 /*************************************** ...

  4. POJ 1470 Closest Common Ancestors(LCA 最近公共祖先)

    其实这是一个裸求LCA的题目,我使用的是离线的Tarjan算法,但是这个题的AC对于我来说却很坎坷……首先是RE,我立马想到数组开小了,然后扩大了数组,MLE了……接着把数组调整适当大小,又交了一发, ...

  5. POJ 1470 Closest Common Ancestors LCA题解

    本题也是找LCA的题目,只是要求多次查询.一般的暴力查询就必定超时了,故此必须使用更高级的方法,这里使用Tarjan算法. 本题处理Tarjan算法,似乎输入处理也挺麻烦的. 注意: 由于查询的数据会 ...

  6. POJ 1470 Closest Common Ancestors (LCA,离线Tarjan算法)

    Closest Common Ancestors Time Limit: 2000MS   Memory Limit: 10000K Total Submissions: 13372   Accept ...

  7. poj1470 Closest Common Ancestors [ 离线LCA tarjan ]

    传送门 Closest Common Ancestors Time Limit: 2000MS   Memory Limit: 10000K Total Submissions: 14915   Ac ...

  8. POJ 1470 Closest Common Ancestors 【LCA】

    任意门:http://poj.org/problem?id=1470 Closest Common Ancestors Time Limit: 2000MS   Memory Limit: 10000 ...

  9. poj----(1470)Closest Common Ancestors(LCA)

    Closest Common Ancestors Time Limit: 2000MS   Memory Limit: 10000K Total Submissions: 15446   Accept ...

随机推荐

  1. iOS测试-如何指标量化app耗电量和性能XCTest Metrics

    对于app端的专项测试,Android端我们可以用adb或者一些三方工具进行(例如itest)进行实时的性能监控,iOS端的话也可以用用一些三方的工具,但是需要嵌入到我们的项目当中,今天来介绍下Xco ...

  2. WebGL的shader

    WebGL的shader(着色器)有2种:vertexShader(定点着色器)和 fragmentShader(片段着色器) 顶点着色器:定义点的位置.大小 片元着色器:定义画出来的物体的材质(颜色 ...

  3. Linux之基础命令

    常用命令 查看ip地址的两种方式 ifconfig ip addr show Linux的两种ip地址: 127.0.0.1 本机回环地址 0.0.0.0 全网地址/绑定所有网卡/所有地址 Linux ...

  4. form 表单提交数据和文件(fromdata的使用方法)

    <!-- 数据和文件一次性提交 --> <form class="form_meren" id="mainForm" name="m ...

  5. Js中Array常用方法小结

    说起Array的方法,不免让人皱一下眉头,下面我们从增删改查角度依次来总结. 1.增 push: 将传入的参数 ,插入数组的尾部,并返回新数组的长度.不管传入参数为一个值还是一个数组,都作为插入数组的 ...

  6. 第11组 Beta冲刺(3/5)

    第11组 Beta冲刺(3/5)   队名 不知道叫什么团队 组长博客 https://www.cnblogs.com/xxylac/p/12006665.html 作业博客 https://edu. ...

  7. nodeJS 项目如何运行

    nodeJS 项目如何运行 一.总结 一句话总结: nodejs项目根目录中用node xx.js 或是 node xx运行 打开 window的 cmd 命令窗口,使用 cd 命令跳转到 nodeJ ...

  8. 01-背包---P2663 越越的组队

    P2663 越越的组队 题解 是这题数据水还是...(数据怎么知道我人数有没有超一半啊) 简化题目: 把n个数分成两组,使得较小的一组在不超过n个数总和一半的情况下和最大 (较小的一组之和肯定不超过总 ...

  9. ajax传参数json对象到后台获取

    类型1 var version = $("#version").val(); var ids[i] = ("127.0.0.1","192.168.1 ...

  10. <JavaScript> 寄生继承详解

    // 将原型继承和非原型继承组合为一体的继承方式叫做组合继承,但是这种方法的继承是有一点小缺陷的,下级函数继承了无用的属性,所以我们有了寄生继承来解决污染问题; //创建上级构造函数-食物 funct ...