题解来自出题人的blog:http://www.huangshenno1.cn/blog/?p=161
就是分块lca的思想
下面上一发自己写的代码
#include<iostream>
#include<sstream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<queue>
#include<stack>
#include<math.h>
#include<map>
#include<time.h>
#include<set>
#include<string>
#include<vector>
#include<algorithm>
using namespace std;
#define inf 0x7fffffff
#define lc l,m,index<<1
#define rc m+1,r,index<<1|1
#define max_n 100005
#define mod 100007
#define LL __int64
#define max_log 20
int n,m;
int t;
int q[max_n][2];
int depth[max_n];
bool vis[max_n];
bool vis1[max_n];
int ans[max_n];
int parent[30][max_n];
vector<int>G[max_n];
struct node
{
int index;
int step;
};
queue<node>p;
void dfs(int v,int p,int d)
{
parent[0][v]=p;
depth[v]=d;
for(int i=0;i<G[v].size();i++)
{
if(G[v][i]!=p)
dfs(G[v][i],v,d+1);
}
}
void add_edge(int u,int v)
{
G[u].push_back(v);
G[v].push_back(u);
}
//返回u,v两点之间的距离
int lcanum(int u,int v)
{
int xx=0;
if(depth[u]>depth[v])
swap(u,v);
for(int k=0;k<max_log;k++)
{
if((depth[v]-depth[u])>>k & 1)
{
xx+=(int)pow(2,k);
v=parent[k][v];
}
}
if(u==v)
return xx;
for(int k=max_log-1;k>=0;k--)
{
if(parent[k][v]!=parent[k][u])
{
xx+=2*(int)pow(2,k); //然而这里最开始忘记乘二,WA8发。。
u=parent[k][u];
v=parent[k][v];
}
}
return xx+2;
}
//更新这颗树
void bfs()
{
while(!p.empty())
{
node s=p.front();
p.pop();
node next;
for(int i=0;i<G[s.index].size();i++)
{
if(!vis1[G[s.index][i]]) //不是红点且没被用过
{
//printf("%d",G[s.index][i]);
ans[G[s.index][i]]=s.step+1;
next.index=G[s.index][i];
next.step=s.step+1;
vis1[G[s.index][i]]=1;
p.push(next);
}
}
}
}
//初始化
void init()
{
memset(vis,0,sizeof(vis));
dfs(1,-1,0);
// for(int i=1;i<=n;i++)
// printf("d[%d] == %d\n",i,depth[i]);
for(int k=0;k+1<max_log;k++)
{
for(int v=1;v<=n;v++)
{
if(parent[k][v]<0) parent[k+1][v]=-1;
else
parent[k+1][v]=parent[k][parent[k][v]];
}
}
}
int main()
{
scanf("%d",&t);
while(t--)
{
//输入加初始化
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
G[i].clear();
for(int i=0;i<n-1;i++)
{
int u,v;
scanf("%d%d",&u,&v);
add_edge(u,v);
}
for(int i=0;i<m;i++)
scanf("%d%d",&q[i][0],&q[i][1]);
init();
//分为sqrt(m)块进行计算
int index=0;
int x=(int)sqrt(m);
while(index<m)
{
int end=index+x>m?m:index+x;
//每一块里的操作
for(int i=index;i<end;i++)
{
vis[q[i][0]]=1;
ans[q[i][0]]=0;
//更新yi~yk
for(int j=i;j<end;j++)
{
int num=lcanum(q[i][0],q[j][1]);
if(num<ans[q[j][1]]) ans[q[j][1]]=num;
}
printf("%d\n",ans[q[i][1]]);
}
//重新构造这颗树
memset(vis1,0,sizeof(vis1));
for(int i=1;i<=n;i++)
{
node e;
e.step=0;
if(vis[i])
{
vis1[i]=1;
e.index=i;
p.push(e);
}
}
bfs();
index+=x;
}
}
return 0;
}