Innumerable Ancestors
HDU - 6031题意:
寻找两个集合的LCA的最深深度;
第一种方法暴力:
就是将AB集合中结点按照深度递减排序以后循环查找,当已得到答案大于等于当前深度时结束循环;
代码:
#include <iostream>
#include<algorithm>
#include<cstdio>
#include<string>
#include<cstring>
#include<vector>
using namespace std;
const int maxn=1e5+5;
int p[maxn][30];
int a[maxn];
int b[maxn];
int deep[maxn];
int m,n;
vector<int> eg[maxn];
void dfs(int fr,int u,int de)
{
deep[u]=de;
for(int i=1; (1<<i)<=n; i++)
{
if(p[u][i-1]!=-1)
p[u][i]=p[p[u][i-1]][i-1];
}
for(int i=0; i<eg[u].size(); i++)
{
int v=eg[u][i];
if(v==fr)
continue;
p[v][0]=u;
dfs(u,v,de+1);
}
}
void init()
{
memset(p,-1,sizeof(p));
// memset(deep,0,sizeof(deep));
dfs(-1,1,1);
}
int lca(int a,int b)
{
if(deep[a]<deep[b]) swap(a,b);
int t;
for(int i=0; (1<<i)<=deep[a]; i++)
{
t=i;
}
for(int i=t; i>=0; i--)
{
if((deep[a]-(1<<i))>=deep[b])
a=p[a][i];
}
if(a==b)
return a;
for(int i=t; i>=0; i--)
{
if(p[a][i]!=-1&&p[a][i]!=p[b][i])
{
a=p[a][i];
b=p[b][i];
}
}
return p[a][0];
}
int cmp(int a,int b)
{
return deep[a]>deep[b];
}
int main()
{
while(~scanf("%d%d",&n,&m))
{
int ans=0;
for(int i=0; i<=n; i++)
{
eg[i].clear();
}
for(int i=0; i<n-1; i++)
{
int x,y;
scanf("%d%d",&x,&y);
eg[x].push_back(y);
eg[y].push_back(x);
}
init();
while(m--)
{
int ka,kb;
ans=0;
scanf("%d",&ka);
for(int i=0; i<ka; i++)
scanf("%d",&a[i]);
scanf("%d",&kb);
for(int i=0; i<kb; i++)
scanf("%d",&b[i]);
sort(a,a+ka,cmp);
sort(b,b+kb,cmp);
for(int i=0; i<ka; i++)
{
//cout<<"a[i]="<<a[i]<<" de="<<deep[a[i]]<<endl;
if(deep[a[i]]<=ans)
break;
for(int j=0; j<kb; j++)
{
if(deep[b[j]]<=ans)
break;
//cout<<"a="<<a[i]<<" b="<<b[j]<<" lca="<<lca(a[i],b[j])<<endl;
ans=max(ans,deep[lca(a[i],b[j])]);
}
}
printf("%d\n",ans);
}
}
return 0;
}
第二种 lca+二分
二分深度,找出当前深度中A的祖先,然后看B中在当前深度有无相同祖先;
#include <iostream>
#include<algorithm>
#include<cstdio>
#include<string>
#include<cstring>
#include<vector>
#include<map>
using namespace std;
const int maxn=1e5+5;
int p[maxn][30];
int a[maxn];
int b[maxn];
int deep[maxn];
int m,n;
int ka,kb;
vector<int> eg[maxn];
void dfs(int fr,int u,int de)
{
deep[u]=de;
for(int i=1; (1<<i)<=n; i++)
{
if(p[u][i-1]!=-1)
p[u][i]=p[p[u][i-1]][i-1];
}
for(int i=0; i<eg[u].size(); i++)
{
int v=eg[u][i];
if(v==fr)
continue;
p[v][0]=u;
dfs(u,v,de+1);
}
}
void init()
{
memset(p,-1,sizeof(p));
dfs(-1,1,1);
}
int get(int u,int de)
{
if(de<0) return -1;
if(de==0) return u;
else
{
for(int i=20;i>=0;i--)
{
if(de>=(1<<i))
{
u=p[u][i];
de-=(1<<i);
}
}
}
return u;
}
map<int,int> mp;
int check(int depth)
{
mp.clear();
for(int i=0;i<ka;i++)
{
int de=deep[a[i]]-depth;
int v=get(a[i],de);
if(v!=-1)
{
mp[v]=1;
// if(depth==2)
// cout<<"v="<<v<<endl;
}
}
for(int i=0;i<kb;i++)
{
int de=deep[b[i]]-depth;
int v=get(b[i],de);
// if(depth==2)
// cout<<" bv="<<v<<endl;
if(v!=-1&&mp[v])
return 1;
}
return 0;
}
int solve(int l,int r)
{
while(l+1<r)
{
//cout<<l<<" "<<r<<endl;
int mid=(l+r)>>1;
if(check(mid))
l=mid;
else
r=mid-1;
}
if(check(r))
return r;
return l;
}
int main()
{
while(~scanf("%d%d",&n,&m))
{
int ans=0;
for(int i=0; i<=n; i++)
{
eg[i].clear();
}
for(int i=0; i<n-1; i++)
{
int x,y;
scanf("%d%d",&x,&y);
eg[x].push_back(y);
eg[y].push_back(x);
}
init();
while(m--)
{
int l,r=0;
ans=0;
scanf("%d",&ka);
for(int i=0; i<ka; i++)
{
scanf("%d",&a[i]);
r=max(r,deep[a[i]]);
}
scanf("%d",&kb);
for(int i=0; i<kb; i++)
scanf("%d",&b[i]);
ans=solve(1,r);
printf("%d\n",ans);
}
}
return 0;
}