[BZOJ2684][USACO 2004 FEB]距离询问

来源:互联网 发布:winaip阅读器软件下载 编辑:程序博客网 时间:2024/05/23 13:03
题目描述
FJ有N(2 <= N <= 40,000)个农场,编号从1..N。有M(1 <= M < 40,000)条水平或者垂直的道路连接这些农场(1 <= length <= 1000)。下图是有7个农场的例子,括号中的数字表示道路的长度:
           F1 --- (13) ---- F6 --- (9) ----- F3
            |                                 |
           (3)                                 |
            |                                 (7)
           F4 --- (20) -------- F2             |
            |                                   |
           (2)                                F5
            | 
           F7 
每个农场最多只与它上、下、左、右的农场相连。任意两个农场之间,只有唯一的一条路径。

现在给出K个询问,形如:X  Y,表示请你回答编号为X的农场与编号为Y的农场之间的路径长度


输入
 第1行:2个整数 N 和 M,意义如前所述
接下来M行,每行4个变量F1, F2, L, D 描述一条道路, F1 和  F2 是这条道路所连接的两个农场的编号, L 是这条道路的长度, D 是这条道路从F1到F2的方向,即 'N', 'E', 'S', 'W' 这4个字母之一,分别表示北,东,南,西
接下来1行上有1个整数K,表示询问的次数K (1 <= K <= 10,000)

接下来K行,每行2个整数X,Y,表示询问X和Y之间的最短距离


输出

对每个询问,在一个单独的行上,用一个整数回答


样例输入
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


样例输出
13
3

36


提示

Farms 2 and 6 are 20+3+13=36 apart.



题解:LCA半裸题,求LCA的过程中同步记录路径最小值


倍增版:

#include<iostream>#include<cstring>#include<cstdlib>#include<cstdio>#include<cmath>#include<algorithm>using namespace std;const int N=40010;const int LOG=30;  int n, m, k;void Getin( int &shu ) {    char c; int f=1; shu=0;    for( c=getchar(); c<'0' || c>'9'; c=getchar() ) if( c=='-' ) f=-1;    for( ; c>='0' && c<='9'; c=getchar() ) shu=shu*10+c-'0';    shu*=f;}  int fir[N], ecnt;struct node{ int e, w, next; }edge[N<<1];void Link( int s, int e, int w ) {    edge[++ecnt].e=e; edge[ecnt].w=w;    edge[ecnt].next=fir[s]; fir[s]=ecnt;    edge[++ecnt].e=s; edge[ecnt].w=w;    edge[ecnt].next=fir[e]; fir[e]=ecnt;}  int fa[N][LOG+5], dep[N], dis[N];void DFS( int r, int f, int d, int l ) {    dep[r]=d; dis[r]=l;    for( int i=fir[r]; i; i=edge[i].next )        if( edge[i].e!=f ) {            fa[edge[i].e][0]=r;            DFS( edge[i].e, r, d+1, l+edge[i].w );        }} void Build() {    DFS( 1, 0, 1, 0 );    for( int j=1; j<=LOG; j++ )        for( int i=1; i<=n; i++ )            fa[i][j]=fa[ fa[i][j-1] ][j-1];}  int getk( int r ,int k ) {    for( int i=0; i<=LOG; i++ )        if( k&( 1<<i ) ) r=fa[r][i];    return r;} int getd( int r, int d ) { return getk( r, dep[r]-d ); } int LCA_Find( int s1, int s2 ) {    if( dep[s1]<dep[s2] ) swap( s1, s2 );    s1=getd( s1, dep[s2] );    if( s1==s2 ) return s1;    for( int i=LOG; i>=0; i-- )        if( fa[s1][i]!=fa[s2][i] )            s1=fa[s1][i], s2=fa[s2][i];    return fa[s1][0];}  int p1, p2;int Solve() {    int f=LCA_Find( p1, p2 );    return dis[p1]+dis[p2]-dis[f]*2;}  int s, e, w;char c[5];int main() {    Getin(n); Getin(m);    for( int i=1; i<=m; i++ ) {        Getin(s); Getin(e); Getin(w);        Link( s, e, w );        scanf( "%s", c );    }         Build();         Getin(k);    for( int i=1; i<=k; i++ ) {        Getin( p1 ); Getin( p2 );        printf( "%d\n", Solve() );    }    return 0;}


链剖版:

#include<iostream> #include<cstring> #include<cstdlib> #include<cstdio> #include<cmath> #include<algorithm> using namespace std; const int N=40010;     int n, m, k, root; void Getin( int &shu ) {     char c; int f=1; shu=0;     for( c=getchar(); c<'0' || c>'9'; c=getchar() ) if( c=='-' ) f=-1;     for( ; c>='0' && c<='9'; c=getchar() ) shu=shu*10+c-'0';     shu*=f; }       int fir[N], ecnt; struct node{ int e, w, next; }edge[N<<1]; void Link( int s, int e, int w ) {     edge[++ecnt].e=e; edge[ecnt].w=w;    edge[ecnt].next=fir[s]; fir[s]=ecnt;    edge[++ecnt].e=s; edge[ecnt].w=w;    edge[ecnt].next=fir[e]; fir[e]=ecnt;}     int fa[N], dep[N], siz[N], son[N], dis[N];void DFS1( int r, int f, int d, int l ) {    dep[r]=d; siz[r]=1; dis[r]=l;    for( int i=fir[r]; i; i=edge[i].next )        if( edge[i].e!=f ) {            DFS1( edge[i].e, r, d+1, l+edge[i].w );            siz[r]+=siz[ edge[i].e ];            if( siz[ edge[i].e ]>siz[ son[r] ] ) son[r]=edge[i].e;            fa[ edge[i].e ]=r;        }} int top[N];void DFS2( int r, int fa ) {    if( son[r] && son[r]!=r ) top[ son[r] ]=top[r], DFS2( son[r], r );    for( int i=fir[r]; i; i=edge[i].next )        if( edge[i].e!=fa && edge[i].e!=son[r] ) {            top[ edge[i].e ]=edge[i].e;            DFS2( edge[i].e, r );        }}   int LCA( int p1, int p2 ) {    while( top[p1]!=top[p2] ) {        if( dep[ top[p1] ]>dep[ top[p2] ] ) p1=fa[ top[p1] ];        else p2=fa[ top[p2] ];    }    return dep[p1]<dep[p2] ? p1 : p2;}      int p1, p2; int Solve() {     int f=LCA( p1, p2 );     return dis[p1]+dis[p2]-dis[f]*2; }       int s, e, w; char c[5]; int main() {     Getin(n); Getin(m); root=1;    for( int i=1; i<=m; i++ ) {         Getin(s); Getin(e); Getin(w);         Link( s, e, w );         scanf( "%s", c );     }          DFS1( root, -1, 1, 0 );    top[root]=root; DFS2( root, -1 );         Getin(k);     for( int i=1; i<=k; i++ ) {         Getin( p1 ); Getin( p2 );         printf( "%d\n", Solve() );     }     return 0; }