[NOIP模拟赛]单向道路

来源:互联网 发布:王陆807和语料库 知乎 编辑:程序博客网 时间:2024/06/11 12:30
题目描述
一个国家有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;}