题目:
Innumerable Ancestors
Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 131072/131072 K (Java/Others)Total Submission(s): 598 Accepted Submission(s): 188
Problem Description
There is a tree having
n
nodes, labeled from 1 to
n
. The root of the tree is always 1, and the depth of a node
p
is the number of nodes on the shortest path between node
p
and the root.
In computer science, the Lowest Common Ancestor (LCA) of two nodes v and w in a tree is the lowest (i.e. deepest) node that has both v and w as descendants, where we define each node to be a descendant of itself (so if v has a direct connection from w , w is the lowest common ancestor).
You have to answer m queries. Each query gives two non-empty node sets A and B , there might be some nodes in both sets.
You should select one node x from set A , and one node y from set B , x and y can be the same node. Your goal is to maximize the depth of the LCA of x and y .
Please write a program to answer these queries.
In computer science, the Lowest Common Ancestor (LCA) of two nodes v and w in a tree is the lowest (i.e. deepest) node that has both v and w as descendants, where we define each node to be a descendant of itself (so if v has a direct connection from w , w is the lowest common ancestor).
You have to answer m queries. Each query gives two non-empty node sets A and B , there might be some nodes in both sets.
You should select one node x from set A , and one node y from set B , x and y can be the same node. Your goal is to maximize the depth of the LCA of x and y .
Please write a program to answer these queries.
Input
The input contains several test cases, no more than 5 test cases.
In each test case, the first line contains two integers n(1≤n≤100000) and m(1≤m≤100000) , denoting the number of nodes and queries.
For the next n−1 lines,each line contians two integers a and b , denoting a bi-directional edge between node a and b .
Then there are 2m lines, every two lines describes one query.
For each query, the first line describes the set A.
The first integer k(1≤k≤n) denotes the number of nodes in set A , and the next k integers describing the nodes in set A . There might be some nodes appear multiple times in the set.
The second line describes the set B in the same format of set A .
It is guaranteed that ∑k≤100000 in each test case.
In each test case, the first line contains two integers n(1≤n≤100000) and m(1≤m≤100000) , denoting the number of nodes and queries.
For the next n−1 lines,each line contians two integers a and b , denoting a bi-directional edge between node a and b .
Then there are 2m lines, every two lines describes one query.
For each query, the first line describes the set A.
The first integer k(1≤k≤n) denotes the number of nodes in set A , and the next k integers describing the nodes in set A . There might be some nodes appear multiple times in the set.
The second line describes the set B in the same format of set A .
It is guaranteed that ∑k≤100000 in each test case.
Output
For every query, print a number denoting the answer, which means the maximum depth of the LCA.
Sample Input
7 3 1 2 1 3 3 4 3 5 4 6 4 7 1 6 1 7 2 6 7 1 7 2 5 4 2 3 2
Sample Output
3 4 2
给一棵树,然后多次询问,每次询问给出两个集合,从集合A中选择一个点,从集合B中选择一个顶点,使得选出的两个顶点的LCA 的dep最大
#include <bits/stdc++.h>
using namespace std;
vector<int> g[105000];
int n,m,root;
int vs[205000];//dfs序
int dep[205000];//dfs序中结点所在层数
int id[105000];//每个结点在vs数组中的首次出现的下标
int f[205000][21];
int L[205000];//第i位存储i的log
struct node{
int ty,x;//所在集合编号 结点下标
}rec[205000];///离线数组
bool operator<(const node& a,const node& b){
return id[a.x]<id[b.x];//按照在DFS序中出现的先后次序进行排序
};
int tot;
void rmq_init(int tot){
for(int i=0;i<tot;i++) f[i][0]=dep[i];
for(int j=1;j<=20;j++){
for(int i=0;i+(1<<j)-1<tot;i++){
f[i][j]=min(f[i][j-1],f[i+(1<<(j-1))][j-1]);
}
}
}
inline void dfs(int v,int p,int d,int &k){
id[v]=k;
vs[k]=v;
dep[k++]=d;
for(int i=0;i<g[v].size();i++){
if(g[v][i]!=p){
dfs(g[v][i],v,d+1,k);
vs[k]=v;
dep[k++]=d;
}
}
}
void init(int V){
int k=0;
root=1;
dfs(root,-1,0,k);//
rmq_init(V*2-1);
}
inline int query(int a,int b){///返回LCA的dep
int p=L[b-a+1];
return min(f[a][p],f[b-(1<<p)+1][p]);
}
int main(){///1747MS 32600K
for(int i=1;i<=200000;i++) L[i]=31-__builtin_clz(i);//011222233333333 相当于打印log(i) 上取整
while(~scanf("%d%d",&n,&m)){
for(int i=1;i<=n;i++) g[i].clear();
for(int i=1;i<n;i++){
int u,v;
scanf("%d%d",&u,&v);
g[u].push_back(v);
g[v].push_back(u);
}
init(n);
//for(int i=0;i<2*n-1;i++)printf("%d ",vs[i]); printf("\n");
//for(int i=0;i<2*n-1;i++)printf("%d ",dep[i]); printf("\n");
//for(int i=1;i<=n;i++)printf("%d ",id[i]); printf("\n");
while(m--){
int ans=0;
tot=0;
int a;
scanf("%d",&a);
for(int i=1;i<=a;i++){
int x;
scanf("%d",&x);
rec[++tot]=(node){1,x};
}
int b;
scanf("%d",&b);
for(int i=1;i<=b;i++){
int x;
scanf("%d",&x);
rec[++tot]=(node){2,x};
}
sort(rec+1,rec+1+tot);///按id排个序,避免重复查询
int am=-1,bm=-1;
for(int i=1;i<=tot;i++){
//printf("%d %d\n",rec[i].ty,rec[i].x);
if(rec[i].ty==1){
am=id[rec[i].x];///当前集合中处理的元素在字典序中首次出现的位置
if(bm==-1) continue;///尚未遇到另一个集合中的元素
ans=max(ans,query(bm,am));
//printf("%d\n",query(am,id[rec[i].x]));
}
else {
bm=id[rec[i].x];
if(am==-1) continue;
ans=max(ans,query(am,bm));
//printf("%d %d %d\n",am,id[rec[i].x],query(am,id[rec[i].x]));
}
}
printf("%d\n",ans+1);
}
}
}