Description
我们将
A
省简化为由
现在百度陆续开了许许多多的子公司。每家子公司又会在各城市中不断兴建属于该子公司的办公室。
由于各个子公司之间经常有资源的流动,所以公司员工常常想知道,两家子公司间的最小距离。
我们可以把子公司看成一个由办公室组成的集合。那么两个子公司
现在共有 Q 个询问,每次询问分别在两个子公司间的最小距离。
Input
第一行一个正整数
对于每组数据:
第一行两个正整数
N
和
接下来 N−1 行给定所有道路的两端城市编号和道路长度。
接下来
M
行,依次按编号顺序给出各子公司办公室所在位置,每行第一个整数
接下来一个整数
接下来
Q
行,每行两个正整数
【数据范围】
0≤ 边权 ≤100
1≤N,M,Q, 工厂总数 ≤100000
Output
对于每个询问,输出一行,表示答案。
Sample Input
1
3 3
1 2 1
2 3 1
2 1 1
2 2 3
2 1 3
3
1 2
2 3
1 3
Sample Output
1
0
0
Solution
对于一组查询
A
和
Code
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
using namespace std;
#define maxn 100005
struct edge
{
int v,w,next;
}g[2*maxn];
int tot,head[maxn];
void init()
{
tot=0;
memset(head,-1,sizeof(head));
}
void add(int u,int v,int w)
{
g[tot].v=v,g[tot].w=w,g[tot].next=head[u],head[u]=tot++;
}
int Fa[maxn][21],Deep[maxn],Dis[maxn];
void dfs(int u,int fa)
{
Fa[u][0]=fa;
for(int i=1;i<=20;i++)Fa[u][i]=Fa[Fa[u][i-1]][i-1];
for(int i=head[u];~i;i=g[i].next)
{
int v=g[i].v,w=g[i].w;
if(v==fa)continue;
Dis[v]=Dis[u]+w,Deep[v]=Deep[u]+1;
dfs(v,u);
}
}
int Lca(int u,int v)
{
if(Deep[u]<Deep[v])swap(u,v);
for(int i=20;i>=0;i--)
if(Deep[Fa[u][i]]>=Deep[v])
u=Fa[u][i];
if(u==v)return u;
for(int i=20;i>=0;i--)
if(Fa[u][i]!=Fa[v][i])
u=Fa[u][i],v=Fa[v][i];
return Fa[u][0];
}
int get_dis(int u,int v)
{
int lca=Lca(u,v);
return Dis[u]+Dis[v]-2*Dis[lca];
}
int T,n,m,q;
vector<int>v[maxn];
int main()
{
scanf("%d",&T);
while(T--)
{
scanf("%d%d",&n,&m);
init();
for(int i=1;i<n;i++)
{
int u,v,w;
scanf("%d%d%d",&u,&v,&w);
add(u,v,w),add(v,u,w);
}
dfs(1,1);
for(int i=1;i<=m;i++)
{
v[i].clear();
int num,temp;
scanf("%d",&num);
while(num--)
{
scanf("%d",&temp);
v[i].push_back(temp);
}
}
scanf("%d",&q);
while(q--)
{
int x,y,ans;
scanf("%d%d",&x,&y);
ans=get_dis(v[x][0],v[y][0]);
for(int i=0;i<v[x].size();i++)
{
if(!ans)break;
for(int j=0;j<v[y].size();j++)
{
ans=min(ans,get_dis(v[x][i],v[y][j]));
if(!ans)break;
}
}
printf("%d\n",ans);
}
}
return 0;
}