How far away ?
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 7739 Accepted Submission(s): 2769
Problem Description
There are n houses in the village and some bidirectional roads connecting them. Every day peole always like to ask like this "How far is it if I want to go from house A to house B"? Usually it hard to answer. But luckily int this village the answer is always unique, since the roads are built in the way that there is a unique simple path("simple" means you can't visit a place twice) between every two houses. Yout task is to answer all these curious people.
Input
First line is a single integer T(T<=10), indicating the number of test cases.
For each test case,in the first line there are two numbers n(2<=n<=40000) and m (1<=m<=200),the number of houses and the number of queries. The following n-1 lines each consisting three numbers i,j,k, separated bu a single space, meaning that there is a road connecting house i and house j,with length k(0<k<=40000).The houses are labeled from 1 to n.
Next m lines each has distinct integers i and j, you areato answer the distance between house i and house j.
For each test case,in the first line there are two numbers n(2<=n<=40000) and m (1<=m<=200),the number of houses and the number of queries. The following n-1 lines each consisting three numbers i,j,k, separated bu a single space, meaning that there is a road connecting house i and house j,with length k(0<k<=40000).The houses are labeled from 1 to n.
Next m lines each has distinct integers i and j, you areato answer the distance between house i and house j.
Output
For each test case,output m lines. Each line represents the answer of the query. Output a bland line after each test case.
Sample Input
2 3 2 1 2 10 3 1 15 1 2 2 3 2 2 1 2 100 1 2 2 1
Sample Output
10 25 100 100
大致题意:求树上任意两点间的距离,显然就是u,v到根的距离减去他们的LCA到根的距离
由于刚学了LCA 用了三种LCA的方法求了
方法一:离线算法tarjan
#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
const int N = 40000+1000;
int head[N];
int fst[N];
struct Edge
{
int v,w,nxt,id;
}es[N<<1],qury[444];
int cnt,qc;
int ans[222];
int fa[N],ance[N];
void inline add_query(int u,int v,int id)
{
qury[qc].v=v;
qury[qc].id=id;
qury[qc].nxt=fst[u];
fst[u]=qc++;
qury[qc].v=u;
qury[qc].id=id;
qury[qc].nxt=fst[v];
fst[v]=qc++;
}
void inline add_edge(int u,int v,int w)
{
es[cnt].w=w;
es[cnt].v=v;
es[cnt].nxt=head[u];
head[u]=cnt++;
es[cnt].v=u;
es[cnt].w=w;
es[cnt].nxt=head[v];
head[v]=cnt++;
}
int n,m;
bool vis[N];
int getf(int x)
{
return x==fa[x]? x: fa[x]=getf(fa[x]);
}
void Merge(int u,int v)
{
fa[getf(u)]=getf(v);
}
void LCA(int u,int pa)
{
ance[u]=fa[u]=u;
for(int i=head[u];~i;i=es[i].nxt)
{
int v=es[i].v;
if(v==pa) continue;
LCA(v,u);
Merge(u,v);
ance[getf(v)]=u;
}
vis[u]=1;
for(int i=fst[u];~i;i=qury[i].nxt)
{
int v=qury[i].v;
if(vis[v]) ans[qury[i].id]=ance[getf(v)];
}
}
int dp[N];
void makedp(int u,int pa)
{
for(int i=head[u];~i;i=es[i].nxt)
{
int v=es[i].v,w=es[i].w;
if(v==pa) continue;
dp[v]=dp[u]+w;
makedp(v,u);
}
}
void ini()
{
memset(head,-1,sizeof(head));
memset(fst,-1,sizeof(fst));
cnt=qc=0;
memset(vis,0,sizeof(vis));
}
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
ini();
scanf("%d%d",&n,&m);
for(int i=1;i<n;i++)
{
int u,v,w;
scanf("%d%d%d",&u,&v,&w);
add_edge(u,v,w);
}
for(int i=1;i<=m;i++)
{
int u,v;
scanf("%d%d",&u,&v);
add_query(u,v,i);
}
LCA(1,1);
makedp(1,1);
for(int i=0;i<m;i++)
{
int j=i<<1;
printf("%d\n",dp[qury[j].v]+dp[qury[j^1].v]-2*dp[ans[i+1]]);
}
}
return 0;
}
方法二:BFS倍增跳表算法
#include<cstdio>
#include<iostream>
#include<cstring>
#include<queue>
#include<algorithm>
using namespace std;
const int N = 40000+1000;
int head[N];
struct Edge
{
int v,w,nxt;
}es[N<<1];
int cnt;
inline void add_edge(int u,int v,int w)
{
es[cnt].v=v;
es[cnt].w=w;
es[cnt].nxt=head[u];
head[u]=cnt++;
es[cnt].v=u;
es[cnt].w=w;
es[cnt].nxt=head[v];
head[v]=cnt++;
}
int dp[N];
int dep[N];
bool vis[N];
int pa[N][20];
void bfs()
{
queue<int>q;
q.push(1);
pa[1][0]=1;
vis[1]=1;
while(!q.empty())
{
int u=q.front(); q.pop();
for(int i=1;i<20;i++) pa[u][i]=pa[pa[u][i-1]][i-1];
for(int i=head[u];~i;i=es[i].nxt)
{
int v=es[i].v,w=es[i].w;
if(vis[v]==0)
{
vis[v]=1;
dp[v]=dp[u]+w;
pa[v][0]=u;
dep[v]=dep[u]+1;
q.push(v);
}
}
}
}
int LCA(int u,int v)
{
if(dep[u]>dep[v]) swap(u,v);
for(int det=dep[v]-dep[u],i=0;det;i++,det>>=1)
if(det&1) v=pa[v][i];
if(v==u) return v;
for(int i=20-1;i>=0;i--)
if(pa[u][i]!=pa[v][i]) v=pa[v][i],u=pa[u][i];
return pa[u][0];
}
int n,m;
void ini()
{
memset(head,-1,sizeof(head));
cnt=0;
memset(vis,0,sizeof(vis));
dp[1]=0;
}
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
scanf("%d%d",&n,&m);
ini();
for(int i=1;i<n;i++)
{
int u,v,w;
scanf("%d%d%d",&u,&v,&w);
add_edge(u,v,w);
}
bfs();
for(int i=1;i<=m;i++)
{
int u,v;
scanf("%d%d",&u,&v);
int lcav = LCA(u,v);
int ans = dp[u]+dp[v]-2*dp[lcav];
printf("%d\n",ans);
}
}
return 0;
}
#include<cstdio>
#include<iostream>
#include<cstring>
#include<queue>
#include<algorithm>
using namespace std;
const int N = 40000+1000;
int head[N];
struct Edge
{
int v,w,nxt;
}es[N<<1];
int cnt;
inline void add_edge(int u,int v,int w)
{
es[cnt].v=v;
es[cnt].w=w;
es[cnt].nxt=head[u];
head[u]=cnt++;
es[cnt].v=u;
es[cnt].w=w;
es[cnt].nxt=head[v];
head[v]=cnt++;
}
int dp[N];
int index;
int vs[N*2],id[N],dep[N];
int lca[N*2][20];
bool vis[N];
void dfs(int u,int h)
{
vis[u]=1;
id[u]=++index;
vs[index]=u;
dep[u]=h;
for(int i=head[u];~i;i=es[i].nxt)
{
int v=es[i].v,w=es[i].w;
if(vis[v]) continue;
dp[v]=dp[u]+w;
dfs(v,h+1);
vs[++index]=u;
}
}
int mm[N];
void ini()
{
memset(vis,0,sizeof(vis));
memset(head,-1,sizeof(head));
cnt=index=0;
dp[1]=0;
}
int n,m;
int main()
{
mm[0]=-1;
for(int i=1;i<=N-1;i++)mm[i]= (((i-1)&i)==0)? mm[i-1]+1:mm[i-1];
int T;
scanf("%d",&T);
while(T--)
{
scanf("%d%d",&n,&m);
ini();
for(int i=1;i<n;i++)
{
int u,v,w;
scanf("%d%d%d",&u,&v,&w);
add_edge(u,v,w);
}
dfs(1,0);
for(int i=1;i<=index;i++) lca[i][0]=vs[i];
for(int j=1;j<20;j++)
for(int i=1;i+(1<<j)-1<=index;i++)
{
int a=lca[i][j-1],b=lca[i+(1<<(j-1))][j-1];
lca[i][j] = dep[a]<dep[b] ? a:b;
}
for(int i=1;i<=m;i++)
{
int u,v;
scanf("%d%d",&u,&v);
int l=min(id[u],id[v]);
int r=max(id[u],id[v]);
int k=mm[r-l+1];
int a=lca[l][k],b=lca[r-(1<<k)+1][k];
int lcav = dep[a]<dep[b]? a:b;
int ans = dp[u]+dp[v]-2*dp[lcav];
printf("%d\n",ans);
}
}
return 0;
}