Distance Queries
Time Limit: 2000MS | Memory Limit: 30000K | |
Total Submissions: 14738 | Accepted: 5181 | |
Case Time Limit: 1000MS |
Description
Farmer John's cows refused to run in his marathon since he chose a path much too long for their leisurely lifestyle. He therefore wants to find a path of a more reasonable length. The input to this problem consists of the same input as in "Navigation Nightmare",followed by a line containing a single integer K, followed by K "distance queries". Each distance query is a line of input containing two integers, giving the numbers of two farms between which FJ is interested in computing distance (measured in the length of the roads along the path between the two farms). Please answer FJ's distance queries as quickly as possible!
Input
* Lines 1..1+M: Same format as "Navigation Nightmare"
* Line 2+M: A single integer, K. 1 <= K <= 10,000
* Lines 3+M..2+M+K: Each line corresponds to a distance query and contains the indices of two farms.
* Line 2+M: A single integer, K. 1 <= K <= 10,000
* Lines 3+M..2+M+K: Each line corresponds to a distance query and contains the indices of two farms.
Output
* Lines 1..K: For each distance query, output on a single line an integer giving the appropriate distance.
Sample Input
7 6
1 6 13 E
6 3 9 E
3 5 7 S
4 1 3 N
2 4 20 W
4 7 2 S
3
1 6
1 4
2 6
Sample Output
13
3
36
Hint
Farms 2 and 6 are 20+3+13=36 apart.
LCA求最短路,模板题
#include <iostream>
#include <stdio.h>
#include <algorithm>
#include <string.h>
using namespace std;
const int maxn = 40005; //顶点数
const int maxq = 10010; //最多查询次数,根据题目而定,本题中其实每组数据只有一个查询.
//并查集
int f[maxn];//根节点
int find(int x)
{
if (f[x] == -1)
{
return x;
}
return f[x] = find(f[x]);
}
void unite(int u, int v)
{
int x = find(u);
int y = find(v);
if (x != y)
{
f[x] = y;
}
}
//并查集结束
bool vis[maxn];//节点是否访问
int ancestor[maxn];//节点i的祖先
struct Edge
{
int to, next, len;
} edge[maxn * 2];
int head[maxn], tot;
void addedge(int u, int v, int length) //邻接表头插法加边
{
edge[tot].to = v;
edge[tot].len = length;
// printf("%d ",length);
edge[tot].next = head[u];
head[u] = tot++;
}
struct Query
{
int q, next;
int index;//查询编号,也就是输入的顺序
} query[maxq * 2];
int ans[maxn * 2]; //存储每次查询的结果,下表0~Q-1,其实应该开maxq大小的。
int h[maxn], tt;
int Q;//题目中需要查询的次数
int dis[maxn];
void addquery(int u, int v, int index) //邻接表头插法加询问
{
query[tt].q = v;
query[tt].next = h[u];
query[tt].index = index;
h[u] = tt++;
query[tt].q = u; //相当于两次查询,比如查询 3,5 和5,3结果是一样的,以3为头节点的邻接表中有5,以5为头节点的邻接表中有3
query[tt].next = h[v];
query[tt].index = index;
h[v] = tt++;
}
void init()
{
tot = 0;
memset(head, -1, sizeof(head));
tt = 0;
memset(h, -1, sizeof(h));
memset(vis, 0, sizeof(vis));
memset(f, -1, sizeof(f));
memset(ancestor, 0, sizeof(ancestor));
memset(dis, 0, sizeof(dis));
}
void LCA(int u)
{
ancestor[u] = u;
vis[u] = true;
for (int i = head[u]; i != -1; i = edge[i].next) //和顶点u相关的顶点
{
int v = edge[i].to;
// printf("%d ",edge[i].len);
if (vis[v])
{
continue;
}
//dis[v]+=edge[i].len;
dis[v] = dis[u] + edge[i].len;
LCA(v);
unite(u, v);
ancestor[find(u)] = u; //将u的左右孩子的祖先设为u
//dis[find(u)]+=dis[u];
}
for (int i = h[u]; i != -1; i = query[i].next) //看输入的查询里面有没有和u节点相关的
{
int v = query[i].q;
if (vis[v])
{
ans[query[i].index] = ancestor[find(v)];
}
}
}
bool flag[maxn];//用来确定根节点的
int t;
int n, m, u, v, len;
char cc;
int main()
{
scanf("%d%d", &n, &m);
init();
memset(flag, 0, sizeof(flag));
for (int i = 1; i <= m; i++)
{
scanf("%d%d%d %c", &u, &v, &len, &cc);
flag[v] = true; //有入度
addedge(u, v, len);
addedge(v, u, len);
}
scanf("%d", &Q);
for (int i = 0; i < Q; i++)
{
scanf("%d%d", &u, &v);
addquery(u, v, i);
}
int root;
for (int i = 1; i <= n; i++)
{
if (!flag[i])
{
root = i;
// printf("root=%d ",root);
break;
}
}
LCA(root);
// for(int i=1;i<=n;i++)printf("%d ",dis[i]); printf("\n");
for (int i = 0; i < Q; i++)
{
len = dis[query[i << 1].q] + dis[query[i << 1 | 1].q] - dis[ans[i]] * 2;
printf("%d\n", len);
}
return 0;
}