有向边!!!
1 #include<stdio.h> 2 #include<string> 3 #include<map> 4 #include<stdlib.h> 5 #include<iostream> 6 #include<algorithm> 7 #include<math.h> 8 using namespace std; 9 const int maxn = 200005; 10 struct node{ 11 int from,to,next,val; 12 }edge[ maxn<<2 ]; 13 int cnt,head[ maxn ]; 14 map<string,int>mp; 15 16 void addedge( int a,int b,int c ){ 17 edge[ cnt ].from = a; 18 edge[ cnt ].to = b; 19 edge[ cnt ].next = head[ a ]; 20 head[ a ] = cnt++; 21 } 22 int ace[ maxn ];//最近公共祖先 23 int deep[ maxn ]; 24 int fa[ maxn ]; 25 int dis[ maxn ]; 26 27 void init(){ 28 cnt = 0; 29 mp.clear(); 30 memset( fa,0,sizeof(fa) ); 31 memset( head,-1,sizeof( head ) ); 32 } 33 34 void dfs( int now,int now_father,int now_ace,int now_deep,int now_dis ){ 35 fa[ now ]=now_father; 36 deep[ now ]=now_deep; 37 dis[ now ]=now_dis; 38 ace[ now ]=now_ace; 39 for( int i=head[ now ];i!=-1;i=edge[ i ].next ){ 40 int v=edge[ i ].to; 41 // if( fa[ v ]==0 ) 42 dfs( v,now,now_ace,now_deep+1,now_dis+edge[ i ].val ); 43 } 44 } 45 46 int find( int x,int y ){ 47 if( x==y ) return x; 48 if( deep[ x ]>deep[ y ] ){ 49 return find( fa[x],y ); 50 } 51 else{ 52 return find( x,fa[y] ); 53 } 54 } 55 56 int main(){ 57 int ca; 58 scanf("%d",&ca); 59 while( ca-- ){ 60 int n,m; 61 scanf("%d%d",&n,&m); 62 init(); 63 string a,b; 64 int num1,num2; 65 int cc = 1; 66 for( int i=0;i<n-1;i++ ){ 67 cin>>a>>b; 68 if( mp[a]==0 ){ 69 mp[a] = cc; 70 num1 = cc; 71 cc++; 72 } 73 else num1 = mp[a]; 74 if( mp[b]==0 ){ 75 mp[b] = cc; 76 num2 = cc; 77 cc++; 78 } 79 else num2 = mp[b]; 80 addedge( num2,num1,1 ); 81 //addedge( num1,num2,1 ); 82 //cout<<a<<"="<<num1<<" "; 83 //cout<<b<<"="<<num2<<endl; 84 } 85 for( int i=1;i<cc;i++ ){ 86 if( fa[i]==0 ){ 87 dfs( i,-1,i,0,1 ); 88 } 89 } 90 /* 91 for( int i=1;i<cc;i++ ){ 92 printf("now = %d\n",i); 93 printf("dis[%d]=%d ace[%d]=%d fa[%d]=%d deep[%d]=%d\n\n",i,dis[i],i,ace[i],i,fa[i],i,deep[i]); 94 } 95 */ 96 while( m-- ){ 97 cin>>a>>b; 98 num1 = mp[a]; 99 num2 = mp[b]; 100 int father = find( num1,num2 ); 101 if( father==num2 ){ 102 printf("%d\n",abs(deep[num2]-deep[num1])); 103 } 104 else if( father==num1 ){ 105 printf("1\n"); 106 } 107 else{ 108 printf("%d\n",abs(deep[num1]-deep[father])+1); 109 } 110 111 } 112 } 113 return 0; 114 }
再贴一个tarjan版本的。。。
1 /* 2 lca+tarjan 3 */ 4 #include<stdio.h> 5 #include<string.h> 6 #include<stdlib.h> 7 #include<algorithm> 8 #include<iostream> 9 #include<queue> 10 #include<map> 11 #include<math.h> 12 using namespace std; 13 typedef long long ll; 14 //typedef __int64 int64; 15 const int maxn = 100105; 16 const int inf = 0x7fffffff; 17 const double pi=acos(-1.0); 18 const double eps = 1e-8; 19 20 int fa[ maxn ],ace[ maxn ],dis[ maxn ],vis[ maxn ]; 21 struct node{ 22 int u,next; 23 }edge[ maxn<<4 ],ex_edge[ maxn<<4 ]; 24 struct node2{ 25 int u,next,val; 26 }ans_edge[ maxn ]; 27 struct node3{ 28 int u,v,fa; 29 }query[ maxn ]; 30 int cnt,head[ maxn ],ex_cnt,ex_head[ maxn ],ans_cnt,ans_head[ maxn ]; 31 map<string,int>mp; 32 33 void init(){ 34 cnt = ex_cnt = ans_cnt = 0; 35 mp.clear(); 36 memset( ans_head,-1,sizeof( ans_head ) ); 37 memset( ex_head,-1,sizeof( ex_head ) ); 38 memset( head,-1,sizeof( head ) ); 39 } 40 void addedge( int a,int b ){ 41 edge[ cnt ].u = b; 42 edge[ cnt ].next = head[ a ]; 43 head[ a ] = cnt++; 44 } 45 void ex_addedge( int a,int b ){ 46 ex_edge[ ex_cnt ].u = b; 47 ex_edge[ ex_cnt ].next = ex_head[ a ]; 48 ex_head[ a ] = ex_cnt++; 49 } 50 void ans_addedge( int a,int b,int c ){ 51 ans_edge[ ans_cnt ].u = b; 52 ans_edge[ ans_cnt ].val = c; 53 ans_edge[ ans_cnt ].next = ans_head[ a ]; 54 ans_head[ a ] = ans_cnt++; 55 } 56 void make_set( int x ){ 57 fa[x] = x; 58 } 59 60 int file_root; 61 void dfs( int cur ){ 62 if( vis[ cur ]==1 ) return ; 63 vis[ cur ] = 1; 64 file_root = cur; 65 for( int i=ex_head[ cur ];i!=-1;i=ex_edge[ i ].next ){ 66 if( vis[ ex_edge[ i ].u ]==0 ){ 67 dfs( ex_edge[ i ].u ); 68 } 69 } 70 }//寻找根目录 71 72 int find( int x ){ 73 if( fa[x]==x ) return x; 74 return fa[x] = find( fa[x] ); 75 } 76 77 void tarjan_of_lca( int cur,int dist ){ 78 make_set( cur ); 79 vis[ cur ] = 1; 80 dis[ cur ] = dist; 81 for( int i=head[ cur ];i!=-1;i=edge[ i ].next ){ 82 if( vis[ edge[ i ].u ]==0 ){ 83 tarjan_of_lca( edge[ i ].u,dist+1 ); 84 fa[ edge[ i ].u ] = cur; 85 } 86 } 87 for( int i=ans_head[ cur ];i!=-1;i=ans_edge[ i ].next ){ 88 if( vis[ ans_edge[ i ].u ]==1 ){ 89 int father = find( ans_edge[ i ].u ); 90 query[ ans_edge[ i ].val ].fa = father; 91 //printf("cur=%d,nxt=%d,father=%d\n",cur,ans_edge[ i ].u,father); 92 //printf("dis_cur=%d,dis_nxt=%d,dis_fa=%d\n\n",dis[cur],dis[ans_edge[ i ].u],dis[father]); 93 } 94 }//在这里寻找公共祖先,至于原因与dfs的过程有关 95 } 96 97 int main(){ 98 int ca; 99 scanf("%d",&ca); 100 while( ca-- ){ 101 int n,m; 102 scanf("%d%d",&n,&m); 103 init(); 104 string a,b; 105 int f1,f2; 106 int cc = 1; 107 n--; 108 while( n-- ){ 109 cin>>a>>b; 110 if( mp[a]==0 ) mp[a] = cc++; 111 if( mp[b]==0 ) mp[b] = cc++; 112 f1 = mp[a]; 113 f2 = mp[b]; 114 addedge( f2,f1 ); 115 ex_addedge( f1,f2 ); 116 } 117 file_root = -1; 118 memset( vis,0,sizeof( vis ) ); 119 dfs( f1 );//find the root 120 for( int i=1;i<=m;i++ ){ 121 cin>>a>>b; 122 f1 = mp[a]; 123 f2 = mp[b]; 124 ans_addedge( f1,f2,i ); 125 ans_addedge( f2,f1,i );//存边 便于在tarjan的过程中存下最近公共祖先 126 query[ i ].u = f1; 127 query[ i ].v = f2;//query记录询问的节点 128 } 129 memset( vis,0,sizeof( vis ) ); 130 tarjan_of_lca( file_root,0 ); 131 for( int i=1;i<=m;i++ ){ 132 if( query[ i ].u==query[ i ].v ) printf("0\n"); 133 else if( query[ i ].fa==query[ i ].u ) printf("1\n"); 134 else if( query[ i ].fa==query[ i ].v ) printf("%d\n",abs( dis[ query[ i ].u ]-dis[ query[ i ].v ])); 135 else { 136 printf("%d\n",dis[query[ i ].u]-dis[ query[ i ].fa ]+1); 137 } 138 //printf("%d\n",ans[i]); 139 } 140 } 141 return 0; 142 }
lca的tarjan版本过程很重要,在dfs过程中,当遇到询问的一对点时候,就要求出结果ace