UESTC Training for Graph Theory——D、Distance Queries

来源:互联网 发布:奥格斯堡同盟 知乎 编辑:程序博客网 时间:2024/05/18 02:29

Distance Queries

Time Limit: 2000 ms Memory Limit: 65536 kB Solved: 65 Tried: 321

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

* Line 1: Two space-separated integers: N and M

* Lines 2..M+1: Each line contains four space-separated entities, F1,

F2, L, and D that describe a road. F1 and F2 are numbers of

two farms connected by a road, L is its length, and D is a

character that is either 'N', 'E', 'S', or 'W' giving the

direction of the road from F1 to F2.

* 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.

Source

USACO 2004 February

 

/*算法思想:  给了一棵树,现在要算出树上每辆个节点之间的距离  给每个点一个标记,记录这个点到根节点的距离(唯一的),由于是树,根节点随便选谁都一样的  然后两个节点之间的距离就是这两个节点到根的距离的和减去这两个节点的最近公共祖先到根的和  的2倍。  每个节点到根节点的距离可以用一遍dfs就遍历出来了,为了方便,我们可以直接在tarjan里面加上  算当前节点到根节点的距离的操作。这样每次tarjan的过程中,都要对当前的点判断一下他们的公共  祖先是否找出来了,找出来了的话,这个询问就出解了*/#include<iostream>#include<cstdio>#include<cstring>#include<cmath>#define N 40005using namespace std;struct data1{    int st,en,val,next;} edge[2*N];struct data2{    int st,en,id,next;} quer[2*N];int fa[N],head_e[N],head_q[N],dis[N],ans[N];int tot_e,tot_q,n,m;bool vs[N];void make_set(){    for(int i=0;i<N;i++)        fa[i]=i;}int find_set(int x){    if(fa[x]!=x) fa[x]=find_set(fa[x]);    return fa[x];}void merge_set(int x,int y){    fa[y]=x;}void add_edge(int st,int en,int val){    edge[tot_e].st=st;    edge[tot_e].en=en;    edge[tot_e].val=val;    edge[tot_e].next=head_e[st];    head_e[st]=tot_e++;}void add_qure(int st,int en,int id)  //添加询问{    quer[tot_q].st=st;    quer[tot_q].en=en;    quer[tot_q].id=id;    quer[tot_q].next=head_q[st];    head_q[st]=tot_q++;}void tarjan(int u,int len)  //对节点u进行tarjan dfs,len为节点u到根的距离{    dis[u]=len;    vs[u]=true;    int pos=head_e[u];    for(;pos!=-1;pos=edge[pos].next)        if(!vs[edge[pos].en])        {            tarjan(edge[pos].en,len+edge[pos].val);            merge_set(edge[pos].st,edge[pos].en);        }    for(pos=head_q[u];pos!=-1;pos=quer[pos].next)  //对每个询问判断是否找出最近公共祖先了        if(vs[quer[pos].en])            ans[quer[pos].id]=dis[quer[pos].st]+dis[quer[pos].en]-2*dis[find_set(quer[pos].en)];}int main(){    while(scanf("%d%d",&n,&m)!=EOF)    {        memset(head_e,-1,sizeof(head_e));        memset(head_q,-1,sizeof(head_q));        memset(fa,-1,sizeof(fa));        tot_e=tot_q=1;        char s[2];        int a,b,val;        for(int i=1;i<=m;i++)        {            scanf("%d%d%d%s",&a,&b,&val,s);            add_edge(a,b,val);            add_edge(b,a,val);        }        int Q;        scanf("%d",&Q);        for(int i=1;i<=Q;i++)        {            scanf("%d%d",&a,&b);            add_qure(a,b,i);            add_qure(b,a,i);        }        make_set();        memset(vs,0,sizeof(vs));        tarjan(1,0);        for(int i=1;i<=Q;i++)            printf("%d\n",ans[i]);    }    return 0;}