您的位置:首页 > Web前端

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

2017-08-12 07:46 369 查看
题目描述

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
, 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
[LOG+5], dep
, dis
;
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
, 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
, dep
, siz
, son
, dis
;
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
;
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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息