先学习了下tarjan算法的LCA 离线算法 它是先知道询问的结点对 在遍历的时候就已经算出来了
看篇图解 讲的很清楚
1 #include <iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #include<stdlib.h> 6 using namespace std; 7 #define N 100010 8 struct node 9 { 10 int u,v,w,next; 11 }ed[N<<2]; 12 int head[N],t,n,q,dis[N]; 13 int vis[N],ans[N],qhead[N<<2]; 14 int father[N],x[N],y[N]; 15 void init() 16 { 17 t = 0; 18 memset(head,-1,sizeof(head)); 19 memset(qhead,-1,sizeof(qhead)); 20 } 21 void add(int u,int v,int w) 22 { 23 ed[t].u = u; 24 ed[t].v = v; 25 ed[t].w = w; 26 ed[t].next = head[u]; 27 head[u] = t++; 28 } 29 void add1(int u,int v,int d) 30 { 31 ed[t].w = d; 32 ed[t].u = u; 33 ed[t].v = v; 34 ed[t].next = qhead[u]; 35 qhead[u] = t++; 36 } 37 int find(int x) 38 { 39 if(x!=father[x]) 40 father[x] = find(father[x]); 41 return father[x]; 42 } 43 void tarjan(int u) 44 { 45 int i; 46 for(i = qhead[u] ; i!=-1 ; i = ed[i].next) 47 { 48 int v = ed[i].v; 49 if(vis[v]) 50 ans[ed[i].w] = find(v); 51 } 52 for(i = head[u] ; i!=-1 ; i = ed[i].next) 53 { 54 int v = ed[i].v; 55 if(!vis[v]) 56 { 57 vis[v] = 1; 58 dis[v] = dis[u]+ed[i].w; 59 tarjan(v); 60 father[v] = u; 61 } 62 } 63 } 64 int main() 65 { 66 int i,a,b,c; 67 init(); 68 scanf("%d",&n); 69 for(i = 0; i < n ; i++) 70 father[i] = i; 71 for(i = 1 ; i < n ; i++) 72 { 73 scanf("%d%d%d",&a,&b,&c); 74 add(a,b,c); 75 add(b,a,c); 76 } 77 scanf("%d",&q); 78 for(i = 1; i <= q ; i++) 79 { 80 scanf("%d%d",&x[i],&y[i]); 81 add1(x[i],y[i],i); 82 add1(y[i],x[i],i); 83 } 84 vis[0] = 1; 85 tarjan(0); 86 for(i = 1; i <= q ; i++) 87 { 88 printf("%d\n",dis[x[i]]+dis[y[i]]-2*(dis[ans[i]])); 89 } 90 return 0; 91 }