题目描述
一个国家有n个城市和m个双向道路连接他们。技术发展导致道路上行驶的车辆越来越多,越来越快,这导致出现问题:两辆相反方向行驶车辆的道路变得太窄。解决这一问题的方法是将所有道路转为单向道路。
把道路改为单向会付出一些代价,例如以前可达的那些城市中的一些可能在更改后不再可达。政府编制了一系列重要的城市对,必须从第一个城市开始,到达第二个城市。你的任务是确定每条道路的方向,确保存在解决方案使得重要的城市对满足条件。对于某些道路,如果您想要获得解决方案,则无法选择道路的方向。车辆必须从第一个城市开向第二个城市(规定为向右的方向,由字母R表示),或者必须从第二个城市开向第一个(规定为向左的方向,用字母L表示)。然而,对于某些道路,存在某一个解决方案使得它的方向为左,而在另一个(可能是不同的)解决方案中它的方向为右。这时用两个方向的字母B来表示这些道路。
输入格式
第1行:2个整数表示n和m(1≤n,m,p ≤100000)
接下来m行,每行2个整数ai和bi,表示在城市ai和bi之间存在一条道路。在一对城市之间可能存在多条道路,而且一条道路可能连接同一个城市。
接下来1行:1个整数p表示重要城市对的数量接下来p行,每行2个整数xi和yi,表示必须能够从xi出发,走到yi(1≤ai,bi,xi,yi≤n)
输出格式
输出一个长度为m的字符串,第i个字符应当为:
R 如果所有的解决方案中第i条道路都必须向右
L 如果所有的解决方案中第i条道路都必须向左
B 如果某一个解决方案中第i条道路向左,而在另一个解决方案中它的方向为右
输入样例
5 6
1 2
1 2
4 3
2 3
1 3
5 1
2
4 5
1 3
输出样例
BBRBBL
样例说明
以第5条道路"1 3"为例,两个满足条件的解决方案是:LLRLRL 和RLRRLL,所以它的方向为B
题解:缩点+LCA
首先在环中的边一定是B。因此将环缩为点,使原图变为一棵树。再看重要城市对是否是同一个点,不是就找其LCA,标记重要城市对到LCA的路径。思路很简单,就是代码量有点大。
#include<cstdio> #include<algorithm> using namespace std; const int N=100005; const int M=N<<1; 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=1; struct enode{ int e, next; bool flg; } edge[M]; void Elink( int s, int e ) { edge[++ecnt].e=e; edge[ecnt].next=fir[s]; fir[s]=ecnt; edge[++ecnt].e=s; edge[ecnt].next=fir[e]; fir[e]=ecnt; } int n, m, s, e; void Build_map() { Getin(n); Getin(m); for( int i=1; i<=m; i++ ) { Getin(s); Getin(e); if( s==e ) { ecnt+=2; continue; } Elink( s, e ); } } int dfn[N], low[N], dfs_clock, pcnt; bool bri[M], vis[N]; void Tarjan( int r, int laste ) {//找桥 dfn[r]=low[r]=++dfs_clock; for( int i=fir[r]; i; i=edge[i].next ) if( !dfn[ edge[i].e ] ) { Tarjan( edge[i].e, i ); low[r]=min( low[r], low[ edge[i].e ] ); if( dfn[r]<low[ edge[i].e ] ) bri[i]=bri[i^1]=1; } else if( i!=(laste^1) ) low[r]=min( low[r], dfn[ edge[i].e ] ); } void Note( int r, int id ) { low[r]=id; vis[r]=1; for( int i=fir[r]; i; i=edge[i].next ) if( !vis[ edge[i].e ] ) { if( bri[i] ) Note( edge[i].e, ++pcnt ); else Note( edge[i].e, id ); } } int point[N], tcnt, rot[N], rcnt, oppo[M]; struct tnode{ int e, next; } tree[M]; void Tlink( int s, int e ) { tree[++tcnt].e=e; tree[tcnt].next=point[s]; point[s]=tcnt; } void Build_tree() {//将原图缩点为一棵树 for( int i=1; i<=n; i++ ) if( !dfn[i] ) { rot[++rcnt]=i; Tarjan( i, -1 ); Note( i, ++pcnt ); } for( int r=1; r<=n; r++ ) for( int i=fir[r]; i; i=edge[i].next ) if( low[r]!=low[ edge[i].e ] ) Tlink( low[r], low[ edge[i].e ] ), oppo[tcnt]=i;//记录树中的边对应到原图的哪一条边 } int fa[N], dep[N], siz[N], son[N]; void DFS1( int r, int f, int d ) { dep[r]=d; siz[r]=1; for( int i=point[r]; i; i=tree[i].next ) if( tree[i].e!=f ) { DFS1( tree[i].e, r, d+1 ); siz[r]+=siz[ tree[i].e ]; if( siz[ tree[i].e ]>siz[ son[r] ] ) son[r]=tree[i].e; fa[ tree[i].e ]=r; } } int top[N], fae[N], sc[N]; void DFS2( int r, int f ) { sc[r]=r; if( son[r] ) top[ son[r] ]=top[r], DFS2( son[r], r ); for( int i=point[r]; i; i=tree[i].next ) if( tree[i].e!=f && tree[i].e!=son[r] ) { top[ tree[i].e ]=tree[i].e; DFS2( tree[i].e, r ); } else if( tree[i].e==f ) fae[r]=i;//记录当前点与其父亲点之间的边 } 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; } void TCS() { for( int i=1; i<=rcnt; i++ ) { DFS1( low[ rot[i] ], -1, 1 ), top[ low[ rot[i] ] ]=low[ rot[i] ]; DFS2( low[ rot[i] ], -1 ); } } void Find_way() { TCS(); int q; Getin(q); for( int i=1; i<=q; i++ ) { Getin(s); Getin(e); if( low[s]==low[e] ) continue; s=low[s]; e=low[e]; int lca=LCA( s, e ); while( s && s!=lca && dep[ sc[s] ]>dep[lca] ) { if( sc[s]!=s ) s=sc[s]; edge[ oppo[ fae[s] ] ].flg=1; sc[s]=lca; s=fa[s]; } while( e && e!=lca && dep[ sc[e] ]>dep[lca] ) { if( sc[e]!=e) e=sc[e]; edge[ oppo[ fae[e] ]^1 ].flg=1; sc[e]=lca; e=fa[e]; } } } void Print() { for( int i=2; i<=ecnt; i+=2 ) { if( edge[i].flg ) printf( "R" ); else if( edge[i^1].flg ) printf( "L" ); else printf( "B" ); } putchar(10); } int main() { Build_map(); Build_tree(); Find_way(); Print(); return 0; }
[NOIP模拟赛]单向道路
最新推荐文章于 2021-12-28 23:05:45 发布