hdu 2586 How far away ? 離線LCA
阿新 • • 發佈:2017-11-19
相加 ref 雙向 std pid edge markdown syn down
題目鏈接:hadu 2586
題目大意:
城鎮之間互相有道路(雙向邊),且只存在n-1條邊,保證相互可達,求兩點
之間的距離。
思路:
轉化為LCA裸問題,只需要再一邊尋找最近公共祖先的同時,跟
新當前點到根節點的距離dist即可,那麽節點u,v之間的距離為
dist[u]+dist[v]-2*dist[lca(u,v)];
代碼:
#include <iostream>
#include <string.h>
#include <stdio.h>
using namespace std;
const int maxn=40005;
const int maxm=80005 ;
struct enode {
int to,next,w;
} edges[maxm];
struct qnode {
int to,next,id;
} query[405];
//dist[] 節點到根節點的距離
int head_e[maxn],head_q[maxn],f[maxn],vis[maxn],dist[maxn],res[405];
int n,m,u,v,w,cnte=0,cntq=0;//n個節點 m個詢問
inline void addedge(int u, int v, int w) {
edges[cnte].w=w;
edges[cnte].to=v;
edges[cnte].next=head_e[u];
head_e[u]=cnte++;
}
inline void addque(int u, int v, int id) {
query[cntq].id=id;
query[cntq].to=v;
query[cntq].next=head_q[u];
head_q[u]=cntq++;
}
inline void init() {
memset(head_e,-1,sizeof(head_e));
memset(head_q,-1,sizeof(head_q));
memset(vis,0,sizeof(vis));
memset(dist,0,sizeof(dist));
for (int i=1; i<=n; ++i) f[i]=i;
}
int Find(int x) {
return x==f[x] ? x : f[x]=Find(f[x]);
}
void tarjan(int s) {
vis[s]=1;
for(int i=head_e[s]; i!=-1; i=edges[i].next) {
if(!vis[edges[i].to]) {
dist[edges[i].to]=dist[s]+edges[i].w;//跟新到根的距離
tarjan(edges[i].to);
f[edges[i].to]=s;
}
}
for(int i=head_q[s]; i!=-1; i=query[i].next) {
if(vis[query[i].to]==1) {
int z=Find(query[i].to);
//先減去再相加
res[query[i].id]=dist[s]-dist[z]-dist[z]+dist[query[i].to];
}
}
}
int main() {
ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
int t; cin>>t;
while(t--) {
cin>>n>>m;
init();
for(int i=1; i<n; ++i) {
cin>>u>>v>>w;
addedge(u,v,w);
addedge(v,u,w);
}
for(int i=1; i<=m; ++i) {
cin>>u>>v;
addque(u,v,i);
addque(v,u,i);
}
dist[1]=0;
tarjan(1);
for(int i=1; i<=m; ++i) cout<<res[i]<<endl;
}
return 0;
}
hdu 2586 How far away ? 離線LCA