题意:题目很花哨,题意和hdu2586一样(可以说除了输入格式略微不同以外),求两个结点之间的最小距离
输入:第一行结点个数n,边数t,然后问题数目k
思路:每个结点记录一个到根结点的权值大小,然后两个结点减去其lca权值即为答案.在tarjan递归遍历时同时将路径权值相加,得到某结点到根的权值和
由于该题没有给出n的数目,不能开大了所以就定了一个合适的大小(wa了试出的...)
完整代码:
#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<vector>
using namespace std;
const int rmaxn = 80080;
const int qmaxn = 10005;
int t,n,m;
vector<int> query[rmaxn],v[rmaxn],w[rmaxn],num[rmaxn];
int ans[qmaxn], pre[rmaxn],dis[rmaxn];
bool vis[rmaxn];
void tarjan(int x,int y);
int find(int x);
void Union(int x,int y);
void init();
void init()
{
for(int i=1; i<=n; i++)
{
v[i].clear();
w[i].clear();
query[i].clear();
num[i].clear();
pre[i] = i;
dis[i] = 0;
vis[i] = false;
}
}
void tarjan(int cur,int val)
{
vis[cur] = true;
dis[cur] = val;
for(int i=0;i<v[cur].size();i++)
{
int s=v[cur][i];
if(vis[s]) continue;
tarjan(s,val + w[cur][i]);
//father[s]=cur;
Union(cur,s);
}
for(int j=0;j< query[cur].size();j++)
{
int s= query[cur][j];
if(!vis[s]) continue;
ans[num[cur][j]] = dis[cur] + dis[s] - 2*dis[find(s)];
}
}
int find(int x)
{
if(pre[x] != x)
pre[x] = find(pre[x]);
return pre[x];
}
void Union(int x,int y)
{
x = find(x);
y = find(y);
if(x == y) return;
pre[y] = x;
}
int main()
{
int x,y,z,a;
// scanf("%d",&t);
while(~scanf("%d%d",&n,&t))
{
init();
for(int i=1;i<=t;i++)
{
scanf("%d%d%d%c%*c",&x,&y,&z,&a);
//双向连通
v[x].push_back(y);
v[y].push_back(x);
w[x].push_back(z);
w[y].push_back(z);
}
scanf("%d",&m);
for(int i=0;i<m;i++)
{
scanf("%d%d",&x,&y);
//问题记录
query[x].push_back(y);
query[y].push_back(x);
//
num[x].push_back(i);
num[y].push_back(i);
}
tarjan(1,0);
for(int i=0;i<m;i++)
printf("%d\n",ans[i]);
}
return 0;
}