hdu2874(lca / tarjan离线 + RMQ在线)
题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=2874
题意: 给出 n 个顶点 m 条边的一个森林, 有 k 个形如 x y 的询问, 输出 x, y 之间的最短路径.
思路: 如果将森林换成一棵树的话就是一道 lca 模板题了, 不过本题需要稍作改动.
解法1: tarjan
只需要先判断一下 x, y 是否在一颗树里面就 ok 了, 不过这道题的询问有点多, 很容易 mle.
代码:
#include <iostream>
#include <stdio.h>
#include <string.h>
using namespace std; const int MAXN = 1e4 + ;
const int MAX = 1e6 + ;
struct node1{
int v, w, next;
}edge1[MAXN << ]; struct node2{
int u, v, next;
}edge2[MAX << ];//edge1记录树, edge2记录询问 int vis[MAXN], pre[MAXN], dis[MAXN], sol[MAX];//vis[i]标记i是否已经搜索过, pre[i]记录i的根节点, dis[i]记录i到根节点的距离
int head1[MAXN], head2[MAXN], ip1, ip2, cnt; void init(void){
memset(sol, , sizeof(sol));
memset(vis, , sizeof(vis));
memset(dis, , sizeof(dis));
memset(head1, -, sizeof(head1));
memset(head2, -, sizeof(head2));
ip1 = ip2 = cnt = ;
} void addedge1(int u, int v, int w){//前向星
edge1[ip1].v = v;
edge1[ip1].w = w;
edge1[ip1].next = head1[u];
head1[u] = ip1++;
} void addedge2(int u, int v){
edge2[ip2].u = u;
edge2[ip2].v = v;
edge2[ip2].next = head2[u];
head2[u] = ip2++;
} int find(int x){
return pre[x] == x ? x : pre[x] = find(pre[x]);
} void jion(int x, int y){
x = find(x);
y = find(y);
if(x != y) pre[y] = x;
} void tarjan(int u){
pre[u] = u;
vis[u] = cnt;//将不同的联通块标记成不同的数字
for(int i = head1[u]; i != -; i = edge1[i].next){
int v = edge1[i].v;
int w = edge1[i].w;
if(!vis[v]){
dis[v] = dis[u] + w;
tarjan(v);
jion(u, v);
}
}
for(int i = head2[u]; i != -; i = edge2[i].next){
int v = edge2[i].v;
if(vis[v] == cnt) sol[i >> ] = find(v);//只有同一个联通块的顶点才存在lca
}
} int main(void){
int t, n, m, x, y, z;
while(~scanf("%d%d%d", &n, &m, &t)){
init();
for(int i = ; i < m; i++){
scanf("%d%d%d", &x, &y, &z);
addedge1(x, y, z);
addedge1(y, x, z);
}
for(int i = ; i < t; i++){
scanf("%d%d", &x, &y);
addedge2(x, y);
addedge2(y, x);
}
for(int i = ; i <= n; i++){
if(!vis[i]){
cnt++;
dis[i] = ;//顶点到自己的距离为0
tarjan(i);
}
}
for(int i = ; i < t; i++){
int cc = i << ;
int u = edge2[cc].u;
int v = edge2[cc].v;
int lca = sol[i];//sol开两倍空间会超内存
if(!lca) puts("Not connected");
else printf("%d\n", dis[u] + dis[v] - * dis[lca]);
}
}
return ;
}
解法2: lca 转 RMQ
可以先拟个虚根, 另外输出前先判一下 x, y 是否在同一棵树里面即可.
代码:
#include <iostream>
#include <stdio.h>
#include <string.h>
#include <math.h>
using namespace std; const int inf = 1e9;
const int MAXN = 4e4 + ;
struct node{
int v, w, next;
}edge[MAXN << ]; int dp[MAXN << ][]; //dp[i][j]存储deep数组中下标i开始长度为2^j的子串中最小值的下标
int first[MAXN], ver[MAXN << ], deep[MAXN << ];
int vis[MAXN], head[MAXN], dis[MAXN], tag[MAXN], ip, indx, cnt; inline void init(void){
memset(tag, , sizeof(tag));
memset(vis, , sizeof(vis));
memset(head, -, sizeof(head));
ip = ;
indx = ;
cnt = ;
} void addedge(int u, int v, int w){
edge[ip].v = v;
edge[ip].w = w;
edge[ip].next = head[u];
head[u] = ip++;
} void dfs(int u, int h){
vis[u] = ; //标记已搜索过的点
ver[++indx] = u; //记录dfs路径
first[u] = indx; //记录顶点u第一次出现时对应的ver数组的下标
deep[indx] = h; //记录ver数组中对应下标的点的深度
for(int i = head[u]; i != -; i = edge[i].next){
int v = edge[i].v;
if(!vis[v]){
dis[v] = dis[u] + edge[i].w;
dfs(v, h + );
ver[++indx] = u;
deep[indx] = h;
}
}
} void dfs1(int u){
tag[u] = cnt;
for(int i = head[u]; i != -; i = edge[i].next){
if(!tag[edge[i].v]) dfs1(edge[i].v);
}
} void ST(int n){
for(int i = ; i <= n; i++){
dp[i][] = i;
}
for(int j = ; ( << j) <= n; j++){
for(int i = ; i + ( << j) - <= n; i++){
int x = dp[i][j - ], y = dp[i + ( << (j - ))][j - ];
dp[i][j] = deep[x] < deep[y] ? x : y;
}
}
} int RMQ(int l, int r){
int len = log2(r - l + );
int x = dp[l][len], y = dp[r - ( << len) + ][len];
return deep[x] < deep[y] ? x : y;
} int LCA(int x, int y){
int l = first[x], r = first[y];
if(l > r) swap(l, r);
int pos = RMQ(l, r);
return ver[pos];
} int main(void){
int n, m, k, x, y, z;
while(~scanf("%d%d%d", &n, &m, &k)){
init();
for(int i = ; i < m; i++){
scanf("%d%d%d", &x, &y, &z);
addedge(x, y, z);
addedge(y, x, z);
}
for(int i = ; i <= n; i++){
if(!tag[i]){
cnt++;
dfs1(i);
addedge(i, , inf); //拟个虚根0
addedge(, i, inf);
}
}
dis[] = ;
dfs(, );
ST( * n - );
for(int i = ; i < k; i++){
scanf("%d%d", &x, &y);
int lca = LCA(x, y);
if(tag[x] != tag[y]) puts("Not connected");
else printf("%d\n", dis[x] + dis[y] - * dis[lca]);
}
}
return ;
}
hdu2874(lca / tarjan离线 + RMQ在线)的更多相关文章
- hdu2586(lca模板 / tarjan离线 + RMQ在线)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2586 题意: 给出一棵 n 个节点的带边权的树, 有 m 个形如 x y 的询问, 要求输出所有 x, ...
- SPOJ 10628 Count on a tree(Tarjan离线 | RMQ-ST在线求LCA+主席树求树上第K小)
COT - Count on a tree #tree You are given a tree with N nodes.The tree nodes are numbered from 1 to ...
- 最近公共祖先LCA Tarjan 离线算法
[简介] 解决LCA问题的Tarjan算法利用并查集在一次DFS(深度优先遍历)中完成所有询问.换句话说,要所有询问都读入后才开始计算,所以是一种离线的算法. [原理] 先来看这样一个性质:当两个节点 ...
- HDU-2586-How far away(LCA Tarjan离线算法)
链接:https://vjudge.net/problem/HDU-2586 题意: 勇气小镇是一个有着n个房屋的小镇,为什么把它叫做勇气小镇呢,这个故事就要从勇气小镇成立的那天说起了,修建小镇的时候 ...
- poj3728(lca / tarjan离线)
题目链接: http://poj.org/problem?id=3728 题意: 给出一棵带点权值的树, 对于 q 组形如 x, y 的询问, 一个人要从 x 到 y(单向), 他可以在路上任意一点以 ...
- HDU2874 LCA Tarjan
不知道为什么_add2不能只用单方向呢...........调试了好多次,待我解决这个狗血问题 #include <iostream> #include <vector> #i ...
- 洛谷 P3379 【模板】最近公共祖先(LCA)Tarjan离线
题目链接:LCA tarjan离线 这道题目WA无数发,最后还是参考了大神的blog 谁会想到因为一个输入外挂WA呢 大概是我的挂是假挂吧...orz(其实加上外挂,速度提升很多) 用链式前向星保存边 ...
- [CF 191C]Fools and Roads[LCA Tarjan算法][LCA 与 RMQ问题的转化][LCA ST算法]
参考: 1. 郭华阳 - 算法合集之<RMQ与LCA问题>. 讲得很清楚! 2. http://www.cnblogs.com/lazycal/archive/2012/08/11/263 ...
- LCA算法解析-Tarjan&倍增&RMQ
原文链接http://www.cnblogs.com/zhouzhendong/p/7256007.html UPD(2018-5-13) : 细节修改以及使用了Latex代码,公式更加美观.改的过程 ...
随机推荐
- hbase_异常_01_Hbase: Failed to become active master
一.异常现象 启动hbase之后,抛出异常,异常信息如下: master.HMaster: Failed to become active master hbase java.net.ConnectE ...
- Java企业微信开发_05_消息推送之被动回复消息
一.本节要点 1.消息的加解密 微信加解密包 下载地址:http://qydev.weixin.qq.com/java.zip ,此包中封装好了AES加解密方法,直接调用方法即可. 其中,解 ...
- codeforces 655C C. Enduring Exodus(二分)
题目链接: C. Enduring Exodus time limit per test 2 seconds memory limit per test 256 megabytes input sta ...
- Mybatis学习--日志
学习笔记,选自Mybatis官方中文文档:http://www.mybatis.org/mybatis-3/zh/logging.html Logging Mybatis内置的日志工厂提供日志功能,具 ...
- Linux CentOS 6.5 64位 静默安装Oracle11g 云主机
本例: 通过SSH远程连接云主机,上传oracle11g安装包,在centos6.5上无图形化界面静默安装oracle11g. 涉及工具及环境: 1.本地环境windows7+ssh远程连接工具xSh ...
- netsh wlan start hostednetwork
常用的无线网命令: 一.开启系统承载网络模块和新建无线网络命令: netsh wlan set hostednetwork mode=allow ssid=wifi key=12345678说明:ss ...
- ACM学习历程—HDU5585 Numbers(数论 || 大数)(BestCoder Round #64 (div.2) 1001)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5585 题目大意就是求大数是否能被2,3,5整除. 我直接上了Java大数,不过可以对末尾来判断2和5, ...
- css--offsetParent
offsetParent属性返回一个对象的引用,这个对象是距离调用offsetParent的元素最近的(在包含层次中最靠近的),并且是已进行过CSS定位的容器元素. 如果这个容器元素未进行CSS定位, ...
- 洛谷【P1090】合并果子&&洛谷【P1334】瑞瑞的木板
浅谈堆:https://www.cnblogs.com/AKMer/p/10284629.html 合并果子题目传送门:https://www.luogu.org/problemnew/show/P1 ...
- DOM基础知识整理
--<JavaScript高级程序设计>Chapter10学习笔记 一.节点层次 1.Node类型 1)(Node).nodeType属性 节点nodeType属性有12种. 检测node ...