题意:
题目给出一棵树,然后给出 (K) 对点,每对点表示在树上的一条简单路径,问这 (K) 对点共同覆盖的节点有几个。
想法:
- 考虑树上 (lca) 的一个性质:树上两条路径的交点,只存在这两条路径的起始点的两两之间的 (lca) 的深度最深的两个点所构成的路径。如 ((u_{1},v_{1}))、 ((u_{2},v_{2})) 两条路径的交点只存在于 (lca(u_{1},u_{2})), (lca(u_{1},v_{2})), (lca(u_{2},v_{1})), (lca(u_{2},v_{2})) 这四个点中深度最深的两个点所构成的路径上。
- 那么我们就可以通过把 (K) 对点进行遍历,就可以求出公共路径的起始点。
- 已知起始点,那么利用性质:树上两点间的距离是 (deep[u]+deep[v]-2 imes deep[lca(u,v)]) 。
代码:
#include<bits/stdc++.h>
using namespace std;
const int MAXN=1e4+10;
inline int rd()
{
int res = 0,flag = 0;
char ch;
if ((ch = getchar()) == '-')flag = 1;
else if(ch >= '0' && ch <= '9')res = ch - '0';
while ((ch = getchar()) >= '0' && ch <= '9')res = (res<<1) + (res<<3) + (ch - '0');
return flag ? -res : res;
}
int n;
int head[2*MAXN];
int num=0;
struct edg{
int next,to;
}edge[2*MAXN];
void edge_add(int u,int v) //链式前向星存图
{
num++;
edge[num].next=head[u];edge[num].to=v;head[u]=num;
edge[++num].next=head[v];edge[num].to=u;head[v]=num;
}
//---------------------
// lca部分
int dep[MAXN]={0},f[MAXN][23];
void init()
{
for(int i=0;i<2*MAXN;i++){
head[i]=0;
if(i<MAXN){
dep[i]=0;
for(int j=0;j<23;j++)f[i][j]=0;
}
}
num=0;
}
void dfs(int u,int father)//对应深搜预处理f数组
{
dep[u]=dep[father]+1;
for(int i=1;(1<<i)<=dep[u];i++)
{
f[u][i]=f[f[u][i-1]][i-1];
}
for(int i=head[u];i;i=edge[i].next)
{
int v=edge[i].to;
if(v==father)continue;//双向图需要判断是不是父亲节点
f[v][0]=u;
dfs(v,u);
}
}
int Lca(int x,int y)
{
if(dep[x]<dep[y])swap(x,y);
for(int i=20;i>=0;i--)//从大到小枚举使x和y到了同一层
{
if(dep[f[x][i]]>=dep[y])x=f[x][i];
if(x==y)return x;
}
for(int i=20;i>=0;i--)//从大到小枚举
{
if(f[x][i]!=f[y][i])//尽可能接近
{
x=f[x][i];y=f[y][i];
}
}
return f[x][0];//随便找一个**输出
}
//
bool cmp(int x,int y){
return dep[x]>dep[y];
}
/*
int ans;
void dfs2(int u,int fa,int v,int length)
{
if(u==v){
ans=length;
return;
}
for(int i=head[u];i!=0;i=edge[i].next){
if(edge[i].to==fa)continue;
dfs2(edge[i].to,u,v,length+1);
}
//cout<<sum<<endl;
}
*/
int main()
{
int T,CASE=0;
cin>>T;
while(T--){
printf("Case %d:
",++CASE);
init();
n=rd();
for(int i=1;i<n;i++){
int u,v;
u=rd(),v=rd();
edge_add(u,v);
}
dfs(1,0);
int q;
q=rd();
while(q--){
int K;
int nowu,nowv;
K=rd();
int KK=1;
for(int i=1;i<=K;i++){
int u,v;
u=rd(),v=rd();
if(i==1){
nowu=u;
nowv=v;
continue;
}
int p[5];
p[1]=Lca(nowu,u);
p[2]=Lca(nowu,v);
p[3]=Lca(nowv,u);
p[4]=Lca(nowv,v);
sort(p+1,p+5,cmp);
//cout<<p[1]<<" "<<p[2]<<" "<<p[3]<<" "<<p[4]<<endl;
if(p[1]!=p[2]){
nowu=p[1];
nowv=p[2];
}else{
if(dep[p[1]]<dep[Lca(nowu,nowv)]||dep[p[1]]<dep[Lca(u,v)])KK=0;
nowu=p[1];
nowv=p[1];
}
//cout<<nowv<<endl;
}
//cout<<"xxx"<<KK<<" "<<nowu<<" "<<nowv<<endl;
if(KK){
printf("%d
",dep[nowu]+dep[nowv]-2*dep[Lca(nowu,nowv)]+1);
}else{
printf("0
");
}
}
}
}