倍增求LCA
时间复杂度O(nlogn)
模板
#include <cstdio>
#include <algorithm>
#include <cstring>
#include<queue>
using namespace std;
const int maxn = 10007;
const int DEG = 20;
int head[maxn*2],nxt[maxn*2],to[maxn*2],tot;
void init()
{
tot=0;
memset(head,0,sizeof(head));
memset(nxt,0,sizeof(nxt));
}
void add(int u,int v)
{
++tot;
to[tot]=v;
nxt[tot]=head[u];
head[u]=tot;
}
int fa[maxn][DEG]; //fa[i][j]表示结点i的第2^j个祖先
int deg[maxn]; //深度数组
void bfs(int root)
{
queue<int>que;
deg[root]=0;
fa[root][0]=root;
que.push(root);
while(!que.empty())
{
int tmp=que.front();
que.pop();
for(int i=1;i<DEG;i++)
fa[tmp][i]=fa[fa[tmp][i-1]][i-1];
for(int i=head[tmp];i;i=nxt[i])
{
int v=to[i];
if(v==fa[tmp][0]) continue;
deg[v]=deg[tmp]+1;
fa[v][0]=tmp;
que.push(v);
}
}
}
int LCA(int u,int v)
{
if(deg[u]>deg[v]) swap(u,v);
int hu=deg[u],hv=deg[v];
int tu=u,tv=v;
for(int det=hv-hu,i=0;det;det>>=1,i++)
if(det&1) tv=fa[tv][i];
if(tu==tv) return tu;
for(int i=DEG-1;i>=0;i--)
{
if(fa[tu][i]==fa[tv][i])
continue;
tu=fa[tu][i];
tv=fa[tv][i];
}
return fa[tu][0];
}
bool flag[maxn];
int main()
{
int tt,n,u,v;
scanf("%d",&tt);
while(tt--)
{
init();
scanf("%d",&n);
memset(flag,false,sizeof(flag));
for(int i=1;i<n;i++)
{
scanf("%d%d",&u,&v);
add(u,v),add(v,u);
flag[v]=true; // !!!!
}
int root;
for(int i=1;i<=n;i++)
{
if(!flag[i])
{
root=i;
break;
}
}
bfs(root);
scanf("%d%d",&u,&v);
printf("%d
",LCA(u,v));
}
return 0;
}
分析
模板题
SPOJ COT
分析
根据dfs序建主席树,lca求最近公共祖先结点后,正常的按照主席树查询第k大即可