//并查集记录父亲的数组. int father[MAXN]; //并查集的查找函数,有路径压缩功能. int find ( int x ) { return father[x] == x ? x : father[x] = find ( father[x]); } //采用邻接表存储 struct { int v,next,lca,u; }e[2][MAXN<<2]; //分别记录边对和查询数对 int head[2][MAXN]; int cc; //添加边,flag表示模式 void add ( int flag , int u , int v ) { e[flag][cc].u = u; e[flag][cc].v = v; e[flag][cc].next = head[flag][u]; head[flag][u] = cc++; } //标记当前点是否访问过 bool visited[MAXN]; void LCA ( int u ) { father[u] = u; visited[u] = true; //深度优先搜索整棵树 for ( int i = head[0][u]; i != -1 ; i = e[0][i].next ) { int v = e[0][i].v; if ( visited[v] ) continue; LCA ( v ); //从叶节点开始,逐层标记父节点 father[v] = u; } //当前子树已经维护,利用并查集找到当前子树的查询数对的LCA for ( int i = head[1][u]; i != -1 ; i = e[1][i].next ) { int v = e[1][i].v; if ( !visited[v] ) continue; //如果当前u,v都已经访问过,那么一定维护过的子树中 e[1][i].lca = e[1][i^1].lca = find ( v ); } }