Description
Input
Output
Sample Input
3 3 1
1 2
2 3
1 2 3
1 1 3
3 1 3
Output
1
1
3
Data constraint
Hint
样例2、3、4见所附文件
Solution
对于90%的数据
很明显是一道裸的LCA。
对于每一个询问我们就先用倍增或树剖、Tarjan这些算法求出a,b的LCA和b,c的LCA。
很容易可以发现,对于每一个询问,点b到这两个lca中深度较大的点必然属于答案,即
lca为a和b的LCA,lca1为a和c的LCA。
然后,我们在求出a和c的LCA,记为lca2。
如果
那么就是说明lca2属于a到lca2的这条链上,那么答案就加上lca2到lca的距离,即:
对于100%的数据
这题很诡异, 会爆栈,需要打人工栈。
Code
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<stack>
using namespace std;
int n,m,num,cnt=0;
const int N=200005;
int head[N],dep[N],f[N][50];
bool flag[N];
struct node {
int to,next;
}edge[N<<1];
void add(int x,int y) {
edge[cnt].to=y;
edge[cnt].next=head[x];
head[x]=cnt++;
}
stack <int> z;
int LCA(int x,int y) {
if(dep[x]<dep[y])swap(x,y);
if(dep[x]>dep[y]) {
for(int i=log2(dep[x]-dep[y]);i>=0;i--)
if(dep[f[x][i]]>dep[y])x=f[x][i];
x=f[x][0];
}
if(x==y)return x;
for(register int i=log2(dep[x]);i>=0;i--)
if(f[x][i]!=f[y][i])
x=f[x][i],y=f[y][i];
return f[x][0];
}
int main() {
scanf("%d%d%d",&n,&m,&num);
memset(head,-1,sizeof(head));
for(register int i=1;i<n;i++) {
int u,v;
scanf("%d%d",&u,&v);
add(u,v);add(v,u);
}
z.push(1);
f[1][0]=1;
while(!z.empty()) {
int now=z.top();
if(!flag[now]) {
for(register int i=head[now];i!=-1;i=edge[i].next) {
int son=edge[i].to;
if(son==f[now][0])continue;
z.push(son);
f[son][0]=now;
dep[son]=dep[now]+1;
}
flag[now]=1;
} else z.pop();
}
for(register int j=1;j<=log2(n);j++)
for(register int i=1;i<=n;i++)
f[i][j]=f[f[i][j-1]][j-1];
while(m--) {
int a,b,c;
scanf("%d%d%d",&a,&b,&c);
int lca=LCA(a,b),lca1=LCA(b,c),lca2=LCA(a,c);
int ans=dep[b]-max(dep[lca],dep[lca1])+1;
if(dep[lca2]>=dep[lca])ans+=dep[lca2]-dep[lca];
printf("%d\n",ans);
}
}