标签:
链接:
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 11204 Accepted Submission(s): 4079
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <vector>
#include <queue>
#include <stack>
#include <map>
#include <algorithm>
#include <set>
using namespace std;
typedef long long ll;
typedef unsigned long long Ull;
#define MM(a,b) memset(a,b,sizeof(a));
const double eps = 1e-10;
const int inf =0x7f7f7f7f;
const double pi=acos(-1);
const int maxn=40000;
struct Edge{
int to,w;
Edge(int a,int b):to(a),w(b){};
Edge(){};
}e[maxn+10];
struct node{
int to,id;
};
vector<Edge> G[maxn+10];
vector<node> mp[maxn+10];
int vis[maxn+10],query[maxn+10][4],par[maxn+10],dis[maxn+10];
int findr(int u)
{
if(par[u]!=u)
par[u]=findr(par[u]);
return par[u];
}
void unite(int u,int v)
{
int ru=findr(u);
int rv=findr(v);
if(ru!=rv) par[rv]=ru;
}
void tarjan(int u,int val)
{
vis[u]=1;
dis[u]=val;
for(int i=0;i<mp[u].size();i++)
{
int v=mp[u][i].to;
int id=mp[u][i].id;
if(vis[v])
query[id][2]=findr(v);
}
for(int i=0;i<G[u].size();i++)
{
int v=G[u][i].to;
if(vis[v]) continue;
tarjan(v,val+G[u][i].w);
unite(u,v);
}
}
int main()
{
int cas,n,op,u,v,w;
scanf("%d",&cas);
while(cas--)
{
scanf("%d %d",&n,&op);
for(int i=1;i<=n;i++)
{
G[i].clear();
mp[i].clear();
vis[i]=0;
par[i]=i;
}
for(int i=1;i<=n-1;i++)
{
scanf("%d %d %d",&u,&v,&w);
G[u].push_back(Edge(v,w));
G[v].push_back(Edge(u,w));
}
for(int i=1;i<=op;i++)
{
scanf("%d %d",&u,&v);
query[i][0]=u;
query[i][1]=v;
mp[u].push_back((node){v,i});
mp[v].push_back((node){u,i});
}
tarjan(1,0);
for(int i=1;i<=op;i++)
{
int u=query[i][0];
int v=query[i][1];
int r=query[i][2];
printf("%d\n",dis[u]+dis[v]-2*dis[r]);
}
}
return 0;
}
分析:用的lca
1.因为有n-1条边,任意两点之间可达,那么就是一棵树;
2,假设当前是询问u和v两个点,他们的LCA是r,dis[]数组代表从根到点的距离,那么u和v两点之间的距离就是dis[u]+dis[v]-2*dis[r];所以只需要用Tarjan求一求询问的点对的LCA并且记录一下每个点到根(随便哪个点做根都可以)的距离就可以了
HDU 2586 How far away LCA的离线算法 Tarjan
标签:
原文地址:http://www.cnblogs.com/smilesundream/p/5455020.html