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代码,公式更加美观.改的过程 ...
随机推荐
- hdu 4514 湫湫系列故事――设计风景线(求树的直径)
随着杭州西湖的知名度的进一步提升,园林规划专家湫湫希望设计出一条新的经典观光线路,根据老板马小腾的指示,新的风景线最好能建成环形,如果没有条件建成环形,那就建的越长越好. 现在已经勘探确定了n个位置 ...
- ReactJS结合ES6入门Template
一.前言 二.介绍 ReactJS ECMAScript 6 三.入门DEMO "Hello,XXX“ 输出 ES5写法 <div id="example"> ...
- Git_学习_06_ 放弃本地修改
一.未使用 git add 缓存代码时 git checkout -- filepathname // 放弃某个文件 git checkout . // 放弃所有文件 git checkout . 用 ...
- 异常之: The server time zone value '�й���ʱ��' is unrecognized or represents more than one time zone.
在 MySQL 中执行命令试下: set global time_zone=’+8:00’ 设置为东8区 就不报错了. show variables like '%time_zone%'; 解释:在 ...
- hdu5612 Baby Ming and Matrix games (dfs加暴力)
Baby Ming and Matrix games Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/65536 K (Ja ...
- jqgrid--api,官网demo,编辑
api参考: http://blog.csdn.net/hurryjiang/article/details/7551477 官网demo: http://www.trirand.com/blog/j ...
- 照片Urls
http://img.my.csdn.net/uploads/201402/16/1392530364_7835.jpg http://img.my.csdn.net/uploads/201402/1 ...
- idea-spark-sbt 打包jar
1.打开idea下的terminal窗口 2.只打包部分项目 sbt insight-import/clean insight-import/assembly 这表示只打包主目录下的insight- ...
- Linux统计文件夹占用空间大小--du命令基本用法
命令行环境下要知道linux系统里一个文件夹以及其包含的文件实际所占用的空间大小,linux自带的命令 du可以很好地满足需求. 其他的用法我就不一一写出来了,就列本人觉得会用得最多的,直接上: $ ...
- Python图片识别——人工智能篇
一.安装pytesseract和PIL PIL全称:Python Imaging Library,python图像处理库,这个库支持多种文件格式,并提供了强大的图像处理和图形处理能力. 由于PIL仅 ...