最近公共祖先问题,求的是中两个节点的最近公共祖先。使用了一个带并查集的离线算法。
#include <stdio.h>
const int LEN = 10005;
int p[LEN];
void make ( int n )
{
for ( int i=0; i<n; i++ )
{
p[i] = -1;
}
}
int find ( int a )
{
if ( p[a] < 0 )
{
return a;
}
int r = find ( p[a] );
p[a] = r;
return r;
}
void un ( int a, int b )
{
int ra = find ( a );
int rb = find ( b );
p[rb] = ra;
}
struct
{
int c;/**//*记录结点的入度*/
int last;/**//*记录最后一个节点的地址*/
int next;
}tab[LEN];/**//*邻接链表头,记录最后一个节点的地址*/
typedef struct
{
int num;
int next;
}type;
type node[LEN*2];
int next1; /**//*下一个可以使用的位置*/
void initm ( int n )
{
next1 = 0;
for ( int i=0; i<n; i++ )
{
tab[i].c = 0;
tab[i].last = -1;
tab[i].next = -1;
}
}
void adde ( int b, int e )/**//*增加一条边*/
{
node[next1].num = e;
node[next1].next = -1;
if ( tab[b].next >= 0 )
{
node[ tab[b].last ].next = next1;
}
else
{
tab[b].next = next1;
}
tab[b].last = next1;
tab[e].c ++;
next1 ++;
}
struct
{
int next;
int last;
}que[LEN];
type q[LEN*2];
int next2;
void initq ( int n )
{
next2 = 0;
for ( int i=0; i<n; i++ )
{
que[i].last = -1;
que[i].next = -1;
}
}
void addq ( int b, int e )/**//*增加一条边*/
{
q[next2].num = e;
q[next2].next = -1;
if ( que[b].next >= 0 )
{
q[ que[b].last ].next = next2;
}
else
{
que[b].next = next2;
}
que[b].last = next2;
next2 ++;
}
int color[LEN];
void initc ( int n )
{
for ( int i=0; i<n; i++ )
{
color[i] = 0;
}
}
void lca ( int p )
{
for ( int i=tab[p].next; i!=-1; i=node[i].next )
{
lca ( node[i].num );
un ( p, node[i].num );
}
for ( i=que[p].next; i!=-1; i=q[i].next )
{
if ( color[ q[i].num ] )
{
printf ( "%d\n", find ( q[i].num ) + 1 );
}
}
color[p] = 1;
}
int main ()
{
int t;
int n;
int b, e;
scanf ( "%d", &t );
while ( t -- )
{
scanf ( "%d", &n );
initm ( n );
for ( int i=0; i<n-1; i++ )
{
scanf ( "%d%d", &b, &e );
adde ( b-1, e-1 );
}
initq ( n );
scanf ( "%d%d", &b, &e );
addq ( b-1, e-1 );
addq ( e-1, b-1 );
initc ( n );/**//*初始化颜色*/
make ( n );
for ( i=0; i<n; i++ )
{
if ( ! tab[i].c )
{
break;
}
}
lca ( i );
}
return 0;
}
地址:
http://acm.pku.edu.cn/JudgeOnline/problem?id=1330