POJ 1330
LCA 问题,因为查询操作很少,这次使用离线的Tarjan算法
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <utility>
#include <stack>
#include <vector>
#include <cstring>
#define WHITE -1
#define BLACK 0
using namespace std;
const int maxn= 1e4+3;
vector<vector<int> > fa;
int cl[maxn], mk[maxn];
int qa, qb;
int dad[maxn];
int nca;
void Init(int n)
{
fa.clear();
fa.resize(n+3);
memset(cl, WHITE, sizeof(cl));
memset(mk, -1, sizeof(mk));
}
int Find(int a)
{
if (a== dad[a]){
return dad[a];
}
return dad[a]= Find(dad[a]);
}
void Union(int a, int b)
{
a= Find(a);
b= Find(b);
if (a== b){
return;
}
if (mk[b]< mk[a]){
dad[a]= dad[b];
}
else{
dad[b]= dad[a];
}
}
void dfs(int u, int d)
{
int sn;
mk[u]= d;
dad[u]= u;
for (int i= 0; i< int(fa[u].size()); ++i){
sn= fa[u][i];
dfs(sn, d+1);
dad[sn]= u;
}
if (u==qa && BLACK== cl[qb]){
nca= Find(qb);
return;
}
if (u== qb && BLACK== cl[qa]){
nca= Find(qa);
return;
}
cl[u]= BLACK;
}
int main(void)
{
int T, n;
int nd, snd, rt;
scanf("%d", &T);
while (T--){
scanf("%d", &n);
Init(n);
for (int i= 0; i< n-1; ++i){
scanf("%d %d", &nd, &snd);
fa[nd].push_back(snd);
mk[snd]= 0;
}
scanf("%d %d", &qa, &qb);
for (int i= 1; i<= n; ++i){
if (mk[i]){
rt= i;
break;
}
}
dfs(rt, 1);
printf("%d\n", nca);
}
return 0;
}
使用倍增算法
#include <iostream>
#include <algorithm>
#include <queue>
#include <string>
#include <vector>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cassert>
#include <cmath>
#include <string>
#include <stack>
#include <map>
#include <set>
#include <deque>
using namespace std;
const int INF= 1<<30;
const int maxn= 1e4+5;
const int maxd= 21;
struct Edge
{
int to, next;
Edge(int t= 0, int n= 0) : to(t), next(n) {}
}pool[maxn];
int n;
int tot;
int head[maxn], dep[maxn];
int pre[maxn][maxd];
bool nofa[maxn];
inline void AddEdge(int u, int v)
{
pool[tot].next= head[u];
pool[tot].to= v;
head[u]= tot;
++tot;
}
void bfs(int rt)
{
queue<int> Q;
memset(dep, 0x3f, sizeof(dep));
dep[rt]= 0;
pre[rt][0]= rt;
Q.push(rt);
int cur, d;
while (!Q.empty()){
cur= Q.front();
Q.pop();
for (int i= 1; i < maxd; ++i){
pre[cur][i]= pre[pre[cur][i-1]][i-1];
}
d= dep[cur]+1;
for (int i= head[cur]; ~i; i= pool[i].next){
int to= pool[i].to;
if (pre[cur][0] == to){
continue;
}
dep[to]= d;
pre[to][0]= cur;
Q.push(to);
}
}
}
int LCA(int u, int v)
{
if (dep[v] > dep[u]){
swap(u, v);
}
for (int d= dep[u]-dep[v], i= 0; d; d>>=1, ++i){
if (d & 1){
u= pre[u][i];
}
}
if (u == v){
return u;
}
for (int i= maxd-1; i >= 0; --i){
if (pre[u][i] == pre[v][i]){
continue;
}
u= pre[u][i];
v= pre[v][i];
}
return pre[u][0];
}
int main(int argc, char const *argv[])
{
int kase;
scanf("%d", &kase);
while (kase--){
scanf("%d", &n);
memset(nofa, 0, sizeof(nofa));
memset(head, -1, sizeof(head));
tot= 0;
int u, v;
for (int i= 1; i < n; ++i){
scanf("%d%d", &u, &v);
AddEdge(u, v);
nofa[v]= 1;
}
int rt= -1;
for (int i= 1; i <= n; ++i){
if (!nofa[i]){
rt= i;
break;
}
}
bfs(rt);
scanf("%d%d", &u, &v);
printf("%d\n", LCA(u, v));
}
return 0;
}