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 ...
随机推荐
- PAT 1013 数素数 (20)(代码)
1013 数素数 (20)(20 分) 令P~i~表示第i个素数.现任给两个正整数M <= N <= 10^4^,请输出P~M~到P~N~的所有素数. 输入格式: 输入在一行中给出M和N, ...
- mysql if--then--else --endif 问题
if 0 =resultValue then set @m = 2; else set @m =1; end if if 0 =resultValue then set @m = 2; else se ...
- Java的OOP三大特征之一——多态
OOP(面对对象)三大特征之一——多态 What:多态性是指允许不同类的对象对同一消息作出响应,多态性包括参数化多态性和包含多态性,多态性语言具有灵活.抽象.行为共享.代码共享的优势,很好的解决了应用 ...
- ok,机房小感
难得一次能早来机房,趁今天考完试没啥事,随便写两句牢骚. 学习与编程 老师曾经在招生的时候认真讨论过这个问题,这两者彼此协调并不是一件容易事,很明显,编程是一门大课.它虽然与理科有一定联系,但不代表它 ...
- 2019,UI设计师必备神器
2019年将会是你全新起航的一年,相信你已经制定了很多规划,正在开启第一步的推动. 作为对UI设计师更大程度的支持,今天特意为你分享一款释放你双手的设计神器.让你可以把时间和精力投入到设计本身,这 ...
- python 读取xml
#!/usr/bin/python # -*- coding: UTF- -*- from xml.dom.minidom import parse import xml.dom.minidom # ...
- 2017/2/16:自己ajax+json习惯性写法 代码拼接的写法 +json用post提交乱码的原因
1.先导入jquery的包 2.ajax的写法跟注意点 返回一个list的写法 代码拼接写法: html层: 2.script处 4:在你前面传递参数的时候没有遇到乱码问题的情况下,你使用json并且 ...
- maven打包证(支付)书问题
要将证书文件后缀添加到resource文件夹内范围,添加打包文件后缀(include) 添加maven配置: <resources> <resource> <direct ...
- PHP array
一.数组操作的基本函数 数组的键名和值 array_values($arr);获得数组的值 array_keys($arr);获得数组的键名 array_flip($arr);数组中的值与键名互换(如 ...
- Java数据类型的转换
Java数据类型,从小到大排序 byte ,short ,int ,long ,float, double,char 1.小数据类型转换大的数据类型,自动转换 int a = 3; double b ...