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 1026 程序运行时间(15)(C++&Java&Python)
1026 程序运行时间(15)(15 分) 要获得一个C语言程序的运行时间,常用的方法是调用头文件time.h,其中提供了clock()函数,可以捕捉从程序开始运行到clock()被调用时所耗费的时间 ...
- iOS.UITableView.SectionIndex
1. 为tableview中section建立索引来加速tableview的滚动. http://nshipster.com/uilocalizedindexedcollation/ 2. 获取汉字的 ...
- swift 要点
swift 基本语法注意点 通常来说,编程语言教程中的第一个程序应该在屏幕上打印“Hello, world”.在 Swift 中,可以用一行代码实现 print("Hello, world! ...
- CreateToolhelp32Snapshot 以及 EnumProcesses
RT,请教如何获得Windows任务管理器中所显示的进程列表. CreateToolhelp32Snapshot 以及 EnumProcesses 这些方法我都试过了,但是这两种方法得到的结果和任务管 ...
- ubuntu 安装jdk7小结(转载)
ubuntu 安装jdk7小结 目录(?)[+] ubuntu 安装jdk7,现在来总结一下:第一步:下载jdk-7-linux-i586.tar.gz直接在ORACLE的官网中下载就可以:http: ...
- DNA计算机及DNA存储
傅里叶变换到量子水平,可编程元素到原子分子核能,都可以极大的改变有机体(高级有机体都是有寿命的,例如人类),如果可以出现机械体,核能提供能量:并结合类似高级生物大脑的有机体大脑,不断学习进化,甚至优化 ...
- web API分类
什么是Web API? Web API是网络应用程序接口.包含了广泛的功能,网络应用通过API接口,可以实现存储服务.消息服务.计算服务等能力,利用这些能力可以进行开发出强大功能的web应用. 分类 ...
- New users can not log on Win8
方案: http://www.eightforums.com/tutorials/38838-user-profile-service-failed-sign-fix-windows-8-a.html ...
- ManageEngine的EventLog Analyzer许可信息
- 2018.12.29 codeforces 940E. Cashback(线性dp)
传送门 题意:给出一个nnn个数的序列,要求将序列分成若干段,对于一段长度为kkk的自动删去最小的⌊kc⌋\left \lfloor \frac{k}{c} \right \rfloor⌊ck⌋个数 ...