Problem Description
我们将A省简化为由N个城市组成,某些城市之间存在双向道路,而且A省的交通有一个特点就是任意两个城市之间都能通过道路相互到达,且在不重复经过城市的情况下任意两个城市之间的到达方案都是唯一的。聪明的你一定已经发现,这些城市构成了树这样一个结构。
现在百度陆续开了许许多多的子公司。每家子公司又会在各城市中不断兴建属于该子公司的办公室。
由于各个子公司之间经常有资源的流动,所以公司员工常常想知道,两家子公司间的最小距离。
我们可以把子公司看成一个由办公室组成的集合。那么两个子公司A和B的最小距离定义为min(dist(x,y))(x∈A,y∈B)。其中dist(x,y)表示两个办公室之间的最短路径长度。
现在共有Q个询问,每次询问分别在两个子公司间的最小距离。
现在百度陆续开了许许多多的子公司。每家子公司又会在各城市中不断兴建属于该子公司的办公室。
由于各个子公司之间经常有资源的流动,所以公司员工常常想知道,两家子公司间的最小距离。
我们可以把子公司看成一个由办公室组成的集合。那么两个子公司A和B的最小距离定义为min(dist(x,y))(x∈A,y∈B)。其中dist(x,y)表示两个办公室之间的最短路径长度。
现在共有Q个询问,每次询问分别在两个子公司间的最小距离。
Input
第一行一个正整数T,表示数据组数。
对于每组数据:
第一行两个正整数N和M。城市编号为1至N,子公司编号为1至M。
接下来N-1行给定所有道路的两端城市编号和道路长度。
接下来M行,依次按编号顺序给出各子公司办公室所在位置,每行第一个整数G,表示办公室数,接下来G个数为办公室所在位置。
接下来一个整数Q,表示询问数。
接下来Q行,每行两个正整数a,b(a不等于b),表示询问的两个子公司。
【数据范围】
0<=边权<=100
1<=N,M,Q,工厂总数<=100000
对于每组数据:
第一行两个正整数N和M。城市编号为1至N,子公司编号为1至M。
接下来N-1行给定所有道路的两端城市编号和道路长度。
接下来M行,依次按编号顺序给出各子公司办公室所在位置,每行第一个整数G,表示办公室数,接下来G个数为办公室所在位置。
接下来一个整数Q,表示询问数。
接下来Q行,每行两个正整数a,b(a不等于b),表示询问的两个子公司。
【数据范围】
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
Source
2017"百度之星"程序设计大赛 - 初赛(B)
数据比较水,暴力枚举每个子公司然后求LCA就可以。
数据比较水,暴力枚举每个子公司然后求LCA就可以。
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cmath>
#include<vector>
#include<cstdio>
#define N 300000+10
#define INF 0x3f3f3f3f
using namespace std;
int vis[N],id[N],depth[N],dp[N][30],in[N],k,dis[N];
struct node
{
int to,w;
};
vector<node>G[N];
vector<int>e[N];
int Min(int a,int b)
{
return depth[a]<=depth[b]?a:b;
}
void init_rmq(int n)
{
for(int i=1; i<=n; i++)
dp[i][0]=i;
for(int j=1; (1<<j)<=n; j++)
for(int i=1; i+(1<<j)-1<=n; i++)
dp[i][j]=Min(dp[i][j-1],dp[i+(1<<(j-1))][j-1]);
}
void dfs(int v,int p,int d)
{
id[v]=k;
vis[k]=v;
depth[k]=d;
k++;
for(int i=0; i<G[v].size(); i++)
{
if(G[v][i].to!=p)
{
dis[G[v][i].to]=dis[v]+G[v][i].w;
dfs(G[v][i].to,v,d+1);
vis[k]=v;
depth[k]=d;
k++;
}
}
}
void init(int root,int n)
{
k=1;
dfs(root,-1,0);
init_rmq(n*2-1);
}
int query(int l,int r)
{
int k=(int)(log10(r-l+1)/log10(2.0));
int ans=Min(dp[l][k],dp[r-(1<<k)+1][k]);
return vis[ans];
}
int main()
{
int t,n,m,a,b,c,x,y,T,num,q;
cin>>T;
while(T--)
{
cin>>n>>m;
for(int i=0; i<N; i++)
{
G[i].clear();
e[i].clear();
in[i]=0;
dis[i]=0;
}
for(int i=1; i<n; i++)
{
scanf("%d%d%d",&a,&b,&c);
node nd;
nd.to=b,nd.w=c;
G[a].push_back(nd);
nd.to=a,nd.w=c;
G[b].push_back(nd);
in[b]=1;
}
for(int i=1; i<=m; i++)
{
scanf("%d",&t);
while(t--)
{
scanf("%d",&num);
e[i].push_back(num);
}
}
int i;
for(i=1; i<=n; i++)
if(in[i]==0)
break;
init(i,n);
scanf("%d",&q);
while(q--)
{
int mi=INF;
scanf("%d%d",&x,&y);
for(int i=0; i<e[x].size(); i++)
for(int j=0; j<e[y].size(); j++)
{
int ans=query(min(id[e[x][i]],id[e[y][j]]),max(id[e[x][i]],id[e[y][j]]));
mi=min(mi,dis[e[x][i]]+dis[e[y][j]]-2*dis[ans]);
}
printf("%d\n",mi);
}
}
return 0;
}