LCA tarjan+并查集POJ1470
https://www.cnblogs.com/JVxie/p/4854719.html
不错的一篇博客啊,让我觉得LCA这么高大上的算法不是很难啊,嘻嘻嘻
这是个离线算法,现在的粗略理解是输入完毕询问完毕后进行解决的算法
用了并查集
1···选取根节点
2···逐个dfs访问所选节点所有的子节点v
3···1··对于子节点的dfs访问到头之后
3···2··标记,进行询问查询
3···3··如果查询的点访问过,输出其目前祖先
4···回溯,合并边,更新pre数组(并查集)
5.所有节点访问完毕,结束
1.任选一个点为根节点,从根节点开始。
2.遍历该点u所有子节点v,并标记这些子节点v已被访问过。
3.若是v还有子节点,返回2,否则下一步。
4.合并v到u上。
5.寻找与当前点u有询问关系的点v。
6.若是v已经被访问过了,则可以确认u和v的最近公共祖先为v被合并到的父亲节点
模拟别人打了一下代码
#include <iostream>
#include <cstdio>
#include <string.h>
using namespace std;
const int maxn = 1000;
const int maxm = 1000; struct node{
int to,pre;
}e[maxn * maxn],q[maxn * maxn];
int pre[maxn];
bool vis[maxn];
int id[maxn],cnt;
int idq[maxn],cntq;
int in[maxn];
int ans[maxn];
int root;
void init(int n)
{
memset(id,-1,sizeof(id));
memset(idq,-1,sizeof(idq));
cntq = 0;
cnt = 0;
memset(in,0,sizeof(in));
memset(ans,0,sizeof(ans));
memset(vis,0,sizeof(vis));
for(int i = 0;i <= n;i++)
pre[i] = i;
}
void add(int from,int to)
{
e[cnt].to = to;
e[cnt].pre = id[from];
id[from] = cnt++;
}
void addq(int from,int to)
{
q[cntq].to = to;
q[cntq].pre = idq[from];
idq[from] = cntq++;
}
int Find(int x)
{
if(pre[x] == x)return x;
return pre[x] = Find(pre[x]);
}
void join(int u,int v)
{
int fu = Find(u);
int fv = Find(v);
pre[fv] = fu;
}
void LCA(int rt)
{
for(int i = id[rt];~i;i = e[i].pre)
{
int to = e[i].to;
LCA(to);
join(rt,to);
}
vis[rt] = 1;
for(int i = idq[rt];~i;i = q[i].pre)
{
int que = q[i].to;
if(vis[que])
ans[Find(que)]++;
}
}
int main()
{
int n;
while(~scanf("%d",&n))
{
init(n);
int x,y,z;
for(int i = 0;i < n;i++)
{
scanf("%d:(%d)",&x,&y);
for(int j = 0;j < y;j++)
{
scanf("%d",&z);
in[z] = 1;
add(x,z);
}
}
int t;
scanf("%d",&t);
while(t--)
{
while(getchar() !='(');
scanf("%d%d",&x,&y);
addq(x,y);
addq(y,x);
}
while(getchar() != ')');
for(int i = 1;i <= n;i++)
if(!in[i])root = i;
LCA(root);
for(int i = 1;i <= n;i++)
{
if(ans[i] != 0)
printf("%d:%d\n",i,ans[i]);
}
}
return 0;
}
现在我要自己去大一下模板提啦
http://node2.vjmirror.rainng.com/contest/241642#problem/A
题意也是模板题意,很简单,错了两个地方都是小失误。。。。
一个是两个for循环索引都是i
另一个是空间没开够
略略略
#include <iostream>
#include <cstdio>
#include <string.h>
using namespace std;
const int maxn = 1100;
int id[maxn],cnt;
int qid[maxn],qcnt;
struct node
{
int to,pre;
}e[maxn];
struct node2
{
int to,ID,pre;
}q[maxn * 3];
int pre[maxn];
bool vis[maxn];
int ans[maxn];
void init(int n)
{
memset(id,-1,sizeof(id));
memset(qid,-1,sizeof(qid));
memset(vis,0,sizeof(vis));
cnt = qcnt = 0;
for(int i = 0;i <= n;i++)
pre[i] = i;
}
void add(int from,int to)
{
e[cnt].to = to;
e[cnt].pre = id[from];
id[from] = cnt++;
}
void qadd(int from,int to,int I)
{
q[qcnt].to = to;
q[qcnt].pre = qid[from];
q[qcnt].ID = I;
qid[from] = qcnt++;
}
int Find(int x)
{
if(x == pre[x])return x;
return pre[x] = Find(pre[x]);
}
void join(int u,int v)
{
int fu = Find(u),fv = Find(v);
if(fu != fv)
pre[fv] = fu;
}
void tarjan(int rt)
{ //cout<<"cs"<<" "<<rt<<endl;
for(int i = id[rt];~i;i = e[i].pre)
{
int to = e[i].to;
tarjan(to);
join(rt,to);
}
vis[rt] = 1;
for(int i = qid[rt];~i;i = q[i].pre)
{
int que = q[i].to;
if(vis[que])
{
ans[q[i].ID] = Find(que);
//cout<<Find(que)<<endl;
}
}
}
int main()
{
int t,n,m;
scanf("%d",&t);
int cas = 1;
while(t--)
{
scanf("%d",&n);
init(n);
for(int i = 1;i <= n;i++)
{
int n_num,v;
scanf("%d",&n_num);
for(int j = 0;j < n_num;++j)
{
scanf("%d",&v);
add(i,v);
}
}
scanf("%d",&m);
int u,v;
for(int i = 1;i <= m;i++)
{
scanf("%d%d",&u,&v);
qadd(u,v,i);
qadd(v,u,i);
}
tarjan(1);
printf("Case %d:\n",cas++);
for(int i = 1;i <= m;i++)
{
printf("%d\n",ans[i]);
}
}
return 0;
}
LCA tarjan+并查集POJ1470的更多相关文章
- hdu-2874 Connections between cities(lca+tarjan+并查集)
题目链接: Connections between cities Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 32768/327 ...
- Luogu 2245 星际导航(最小生成树,最近公共祖先LCA,并查集)
Luogu 2245 星际导航(最小生成树,最近公共祖先LCA,并查集) Description sideman做好了回到Gliese 星球的硬件准备,但是sideman的导航系统还没有完全设计好.为 ...
- LCA(最近公共祖先)离线算法Tarjan+并查集
本文来自:http://www.cnblogs.com/Findxiaoxun/p/3428516.html 写得很好,一看就懂了. 在这里就复制了一份. LCA问题: 给出一棵有根树T,对于任意两个 ...
- POJ3694 Network - Tarjan + 并查集
Description 给定$N$个点和 $M$条边的无向联通图, 有$Q$ 次操作, 连接两个点的边, 问每次操作后的图中有几个桥 Solution 首先Tarjan找出边双联通分量, 每个双联通分 ...
- BestCoder冠军赛 - 1009 Exploration 【Tarjan+并查集缩点】
[题意] 给一个图,这个图中既有有向边,又有无向边,每条边只能走一次,问图中是否存在环. 最多10^6个点,10^6个无向边,10^6个有向边 [题解] 因为既有有向边又有无向边,所以不能单纯的用ta ...
- NOIP2013 D1T3 货车运输 倍增LCA OR 并查集按秩合并
思路: Kruskal求最大生成树+倍增LCA // by SiriusRen #include <cstdio> #include <cstring> #include &l ...
- codeforce 505 D. Mr. Kitayuta's Technology(tarjan+并查集)
题目链接:http://codeforces.com/contest/505/problem/D 题解:先用tarjan缩点然后再用并查集注意下面这种情况 ‘ 这种情况只需要构成一个大环就行了,也就是 ...
- tarjan求lca :并查集+dfs
//参考博客 https://www.cnblogs.com/jsawz/p/6723221.html#include<bits/stdc++.h> using namespace std ...
- [HDOJ2586]How far away?(最近公共祖先, 离线tarjan, 并查集)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2586 这题以前做过…现在用tarjan搞一发…竟然比以前暴力过的慢………… 由于是离线算法,需要Que ...
随机推荐
- nodejs TLS 只加密,未授权,进一步完善
const tls = require('tls'); const fs = require('fs'); const options = { key: fs.readFileSync('my_key ...
- BZOJ 1977[BeiJing2010组队]次小生成树 Tree - 生成树
描述: 就是求一个次小生成树的边权和 传送门 题解 我们先构造一个最小生成树, 把树上的边记录下来. 然后再枚举每条非树边(u, v, val),在树上找出u 到v 路径上的最小边$g_0$ 和 严格 ...
- python——ADSL拨号程序
这是一个简单的测试实例 说说应用场景吧,都是因为电信搞的奇葩网络结构. 宿舍有若干层,每一层楼的网络拓扑如上图所示,本来是没有问题的,一个楼层接近四十个用户,都拥有一个电信给的宽带拨号账号.但是问题是 ...
- flask部署
https://blog.csdn.net/zhuod/article/details/77850783
- oracle导入sql文件关闭回馈
set feedback off --关闭回馈 set define off --关闭转义关键字
- UVA 10405 Longest Common Subsequence
题目链接:https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&category=16&p ...
- 第五周 PSP 燃尽图 以及 进度条总结
1.PSP DATE START-TIME END-TIME EVENT DELTA TYPE 3.12 9.30 11.30 环境搭建 音乐30min QQ25min ...
- mysql中的handler_read_%
mysql> show status like 'handler_read_%'; +-----------------------+-------+ | Variable_name | Val ...
- Servlet----监听器
监听器的使用: 作用: 监听作用域对象request.session.application的创建.销毁和内容的改变 使用: 创建一个 ...
- Oracle导入的常见语句
登录sql > sqlplus / as sysdba 创建表空间sql > create tablespace TABLESPACE datafile 'e:\tables1.dbf' ...