[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的过程中同步记录路径最小值
倍增版:
链剖版:
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; }
相关文章推荐
- bzoj 3364: [Usaco2004 Feb]Distance Queries 距离咨询 LCA
- BZOJ3364: [Usaco2004 Feb]Distance Queries 距离咨询
- BZOJ 3364: [Usaco2004 Feb]Distance Queries 距离咨询
- LCA【bzoj3364】 [Usaco2004 Feb]Distance Queries 距离咨询
- BZOJ3364: [Usaco2004 Feb]Distance Queries 距离咨询 LCA
- 【BZOJ】3364: [Usaco2004 Feb]Distance Queries 距离咨询
- LCA【bzoj3364】: [Usaco2004 Feb]Distance Queries 距离咨询
- bzoj 3362: [Usaco2004 Feb]Navigation Nightmare 导航噩梦(加权并查集)
- bzoj 3361: [Usaco2004 Jan]培根距离
- bzoj 3361: [Usaco2004 Jan]培根距离
- BZOJ 3365 [Usaco2004 Feb]Distance Statistics 路程统计 树的点分治
- BZOJ_3365_[Usaco2004 Feb]Distance Statistics 路程统计&&POJ_1741_Tree_点分治
- bzoj 3372: [Usaco2004 Feb]Moo University -- Financial Aid 财政补助(set+贪心)
- BZOJ 3367: [Usaco2004 Feb]The Big Game 球赛( dp )
- 【BZOJ 3363】[Usaco2004 Feb]Cow Marathon 奶牛马拉松【树的直径】
- BZOJ 3365: [Usaco2004 Feb]Distance Statistics 路程统计 点分治
- bzoj 3372: [Usaco2004 Feb]Moo University -- Financial Aid 财政补助 二分
- BZOJ_3362_[Usaco2004 Feb]Navigation Nightmare 导航噩梦_并查集
- POJ 1987 BZOJ 3365 USACO 2004 Feb Distance Statistics 路程统计 点分治
- bzoj3362[Usaco2004 Feb]Navigation Nightmare 导航噩梦(带权并查集)