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.
题意:给出n个点,m条边,每个边有一个权值和一个方向,东西南北,WESN。k次询问,问两点间距离,数据保证给的边能构成一颗树。
思路:LCA离线算法:
#include<iostream>
#include<algorithm>
#include<stdio.h>
#include<string>
#include<string.h>
using namespace std;
const int N=1e6+10;
int n,k,m;
int a[N],b[N];
struct node
{
int u,v,w,next,lca;
} edge[N*2],edge1[N*2];
int head[N],head1[N],ip,ip1;
int Father[N],vis[N],dir[N],ans[N];
void init()
{
memset(vis,0,sizeof(vis));
memset(dir,0,sizeof(dir));
memset(head1,-1,sizeof(head1));
memset(head,-1,sizeof(head));
memset(Father,0,sizeof(Father));
ip=ip1=0;
}
void addedge(int u,int v,int w)
{
edge[ip].u=u, edge[ip].v=v, edge[ip].w=w, edge[ip].next=head[u],head[u]=ip++;
}
void addedge1(int u,int v)
{
edge1[ip1].u=u, edge1[ip1].v=v, edge1[ip1].next=head1[u],head1[u]=ip1++;
}
int Find(int x)
{
if(Father[x]==x) return x;
else return Father[x]=Find(Father[x]);
}
void Union(int x,int y)
{
x=Find(x);
y=Find(y);
if(x!=y)
Father[y]=x;
}
void tarjan(int u)
{
vis[u]=1;
Father[u]=u;
for(int i=head[u]; i!=-1; i=edge[i].next)
{
int v=edge[i].v;
int w=edge[i].w;
if(vis[v]) continue;
dir[v]=dir[u]+w;
tarjan(v);
Union(u,v);
}
for(int i=head1[u]; i!=-1; i=edge1[i].next)
{
int v=edge1[i].v;
if(vis[v])
{
edge1[i].lca=edge1[i^1].lca=Father[Find(v)];
}
}
}
int main()
{
while(~scanf("%d%d",&n,&m))
{
init();
for(int i=0; i<m; i++) // 建 图
{
int u,v,w;
char str[10];
scanf("%d%d%d%s",&u,&v,&w,str);
addedge(u,v,w);
addedge(v,u,w);
}
scanf("%d",&k);
for(int i=0; i<k; i++)
{
scanf("%d%d",&a[i],&b[i]);
addedge1(a[i],b[i]);
addedge1(b[i],a[i]);
}
dir[1]=0;
tarjan(1);
for(int i=0; i<k*2; i+=2)
{
int d=dir[a[i/2]]+dir[b[i/2]]-2*dir[edge1[i].lca];
printf("%d\n",d);
}
}
return 0;
}