午时刷题,难甚,遂小憩于桌上,惊醒,于梦中有所得,虽大声曰:吾已得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. hive的两种使用方式

    hive的两种使用方式 1,hive shell的方式 启动命令: bin/hive 2.beeline客户端方式 首先在一个机器上启动hive thrift服务 bin/hiveserver2 在其 ...

  2. JAVA基础知识|抽象类与接口类

    一.抽象类 抽象类:拥有抽象方法的类就是抽象类,抽象类要使用abstract声明 抽象方法:没有方法体的方法,必须要使用abstract修饰 为什么要使用抽象类,抽象方法? 举例来说,如果你定义了一个 ...

  3. 【原创】FltSendMessage蓝屏分析

    INVALID_PROCESS_DETACH_ATTEMPT (6)Arguments:Arg1: 00000000Arg2: 00000000Arg3: 00000000Arg4: 00000000 ...

  4. IdentityServer4入门一

    这几天学习IdentityServer4,感觉内容有点乱,也可能自己水平有限吧.但为了巩固学习的内容,也打算自己理一下思路. 首先IdentityServer解决什么问题? 下图是我们的一个程序的组织 ...

  5. C之指针的加法

    #include<stdio.h> #include<stdlib.h> main() { //char arr [] = {'H','e','l','l','o'}; int ...

  6. python核心模块方法

    ********************os模块: os.remove() 删除文件 os.unlink() 删除文件 os.rename() 重命名文件 os.listdir() 列出指定目录下所有 ...

  7. C++ STL swap_range

    #include <iostream>#include <vector>#include <deque>#include <algorithm> usi ...

  8. java泛型中特殊符号的含义

    java泛型中的标记符含义:  E - Element (在集合中使用,因为集合中存放的是元素) T - Type(Java 类) K - Key(键) V - Value(值) N - Number ...

  9. Python字符串逐字符或逐词反转方法

    Python字符串逐字符或逐词反转方法 这篇文章主要介绍了Python字符串逐字符或逐词反转方法,本文对逐字符或逐词分别给出两种方法,需要的朋友可以参考下 目的 把字符串逐字符或逐词反转过来,这个蛮有 ...

  10. Css3 权重

    Css权重 权重--很多规则应用到同一个元素上时,权重是决定哪个生效的(优先级) 权重等级与权值 行内样式(1000)>ID选择器(100)>类.属性选择器或伪类选择器(10)>元素 ...