Distance Queries
Time Limit: 2000MS |
| Memory Limit: 30000K |
Total Submissions: 11677 |
| Accepted: 4124 |
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.
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算法简介:传送门
这道题很不爽的地方便是输入说明在另一题中(要不要这么懒。。。),贴上那道题的链接
题意:给出k个询问,求每个询问中的节点间的最短距离。
思路:我们可以分别求出各点(i)到根节点的距离,设为dis[i],则对于x,y两点,它们之间的最短距离为dis[x]+dis[y]-2*dis[LCA(x,y)].
- 给出的信息中有方向,但由于最后这些点总会构成一棵树,故可忽略方向.
- 因为是无向图,所以无法知道根节点,所以我们在存边时,同时存反向边(建双向图),然后每个点都可以作为根节点,为方便起见,取1为根节点
- 在求LCA时,同时更新dis值
- 由于n最大可为40000,故无法用邻接矩阵存边,只能用邻接表或vector,我采用了邻接表
#include <cstdio>
#include <cstring>
#include <cmath>
#include <vector>
#include <cstdlib>
#include <algorithm>
using namespace std;
#define mst(a,b) memset((a),(b),sizeof(a))
#define f(i,a,b) for(int i=(a);i<(b);++i)
typedef long long ll;
const int maxn= 40005;
const int mod = 475;
const ll INF = 0x3f3f3f3f;
const double eps = 1e-6;
#define rush() int T;scanf("%d",&T);while(T--)
int n,m;
int cnt;
int vis[maxn];
int pre[maxn];
int head1[maxn],head2[maxn];
int dis[maxn];
struct node
{
int s,t,w,lca,next;
}e1[maxn*2],e2[maxn];
void init()
{
mst(vis,0);
mst(dis,0);
mst(head1,-1);
mst(head2,-1);
for(int i=1;i<=n;i++)
pre[i]=i;
}
int find(int x)
{
int t,r=x;
while(x!=pre[x])
{
x=pre[x];
}
while(r!=x)
{
t=pre[r];
pre[r]=x;
r=t;
}
return x;
}
void join(int a,int b)
{
int A,B;
A=find(a);
B=find(b);
if(A!=B)
pre[B]=A;
}
void add1(int s,int t,int w)
{
e1[cnt].s=s;
e1[cnt].t=t;
e1[cnt].w=w;
e1[cnt].next=head1[s];
head1[s]=cnt++;
}
void add2(int s,int t)
{
e2[cnt].s=s;
e2[cnt].t=t;
e2[cnt].lca=-1;
e2[cnt].next=head2[s];
head2[s]=cnt++;
}
void Tarjan(int now)
{
vis[now]=1;
for(int i=head1[now];i!=-1;i=e1[i].next)
{
int t=e1[i].t;
if(vis[t]==0)
{
int w=e1[i].w;
dis[t]=dis[now]+w;
Tarjan(t);
join(now,t);
}
}
for(int i=head2[now];i!=-1;i=e2[i].next)
{
int t=e2[i].t;
if(vis[t]==1)
{
e2[i].lca=find(t);
e2[i^1].lca=e2[i].lca;
}
}
}
int main()
{
int x,y,w;
int k;
char s[5];
while(~scanf("%d%d",&n,&m))
{
init();
cnt=0;
for(int i=0;i<m;i++)
{
scanf("%d%d%d%s",&x,&y,&w,s);
add1(x,y,w);
add1(y,x,w);
}
cnt=0;
scanf("%d",&k);
for(int i=0;i<k;i++)
{
scanf("%d%d",&x,&y);
add2(x,y);
add2(y,x);
}
Tarjan(1);
for(int i=0;i<k;i++)
{
int now=i*2;
int u=e2[now].s;
int v=e2[now].t;
int lca=e2[now].lca;
int ans=dis[u]+dis[v]-2*dis[lca];
printf("%d\n",ans);
}
}
return 0;
}
接下来是HDOJ上一道几乎一样的题目(当然代码还是重新敲了一下加深印象,上下可能会略有不同)
How far away ?
TimeLimit: 2000/1000 MS (Java/Others) Memory Limit:32768/32768 K (Java/Others)
Total Submission(s): 15532 Accepted Submission(s): 5891
Problem Description
There are n houses in the village and some bidirectional roads connecting them. Everyday peole always like to ask like this "How far is it if I want to go fromhouse A to house B"? Usually it hard to answer. But luckily int thisvillage the answer is always unique, since the roads are built in the way thatthere is a unique simple path("simple" means you can't visit a placetwice) between every two houses. Yout task is to answer all these curiouspeople.
Input
First line is a single integer T(T<=10), indicating the number of test cases.
For each test case,in the first line there are two numbersn(2<=n<=40000) and m (1<=m<=200),the number of houses and thenumber of queries. The following n-1 lines each consisting three numbers i,j,k,separated bu a single space, meaning that there is a road connecting house iand house j,with length k(0<k<=40000).The houses are labeled from 1 to n.
Next m lines each has distinct integers i and j, you areato answerthe distance between house i and house j.
Output
For each test case,output m lines. Each line represents the answer of the query.Output a bland line after each test case.
Sample Input
2
3 2
1 2 10
3 1 15
1 2
2 3
2 2
1 2 100
1 2
2 1
Sample Output
10
25
100
100
#include <cstdio>
#include <cstring>
#include <cmath>
#include <vector>
#include <cstdlib>
#include <algorithm>
using namespace std;
#define mst(a,b) memset((a),(b),sizeof(a))
#define f(i,a,b) for(int i=(a);i<(b);++i)
typedef long long ll;
const int maxn1= 40005;
const int maxn2= 205;
const int mod = 475;
const ll INF = 0x3f3f3f3f;
const double eps = 1e-6;
#define rush() int T;scanf("%d",&T);while(T--)
int n,m;
int cnt;
int pre[maxn1];
int head1[maxn1],head2[maxn1];
int vis[maxn1];
int dis[maxn1];
struct node
{
int s,t,w,lca,next;
}e1[maxn1*2],e2[maxn2*2];
void add1(int s,int t,int w)
{
e1[cnt].s=s;
e1[cnt].t=t;
e1[cnt].w=w;
e1[cnt].next=head1[s];
head1[s]=cnt++;
}
void add2(int s,int t)
{
e2[cnt].s=s;
e2[cnt].t=t;
e2[cnt].lca=-1;
e2[cnt].next=head2[s];
head2[s]=cnt++;
}
void init()
{
mst(vis,0);
mst(dis,0);
mst(head1,-1);
mst(head2,-1);
for(int i=1;i<=n;i++)
pre[i]=i;
}
int find(int x)
{
int t,r=x;
while(x!=pre[x])
{
x=pre[x];
}
while(r!=x)
{
t=pre[r];
pre[r]=x;
r=t;
}
return x;
}
void join(int a,int b)
{
int A,B;
A=find(a);
B=find(b);
if(A!=B)
pre[B]=A;
}
void Tarjan(int now)
{
vis[now]=1;
for(int i=head1[now];i!=-1;i=e1[i].next)
{
int t=e1[i].t;
if(vis[t]==0)
{
int w=e1[i].w;
dis[t]=dis[now]+w;
Tarjan(t);
join(now,t);
}
}
for(int i=head2[now];i!=-1;i=e2[i].next)
{
int t=e2[i].t;
if(vis[t]==1)
{
e2[i].lca=find(t);
e2[i^1].lca=e2[i].lca;
}
}
}
int main()
{
int x,y,w;
rush()
{
scanf("%d%d",&n,&m);
init();
cnt=0;
for(int i=0;i<n-1;i++)
{
scanf("%d%d%d",&x,&y,&w);
add1(x,y,w);
add1(y,x,w);
}
cnt=0;
for(int i=0;i<m;i++)
{
scanf("%d%d",&x,&y);
add2(x,y);
add2(y,x);
}
Tarjan(1);
for(int i=0;i<m;i++)
{
int now=i*2;
int s=e2[now].s;
int t=e2[now].t;
int lca=e2[now].lca;
int ans=dis[s]+dis[t]-2*dis[lca];
printf("%d\n",ans);
}
}
return 0;
}