题意:有 n 个点,由 n-1 条无向边相连,构成了一棵树,每一条边都有各自的权值,然后有m个询问,分别是询问某两点之间的距离。

在树上求两点的路径和,由于树上的路径是确定的,只要求两点分别到他们的LCA的路径和,就是求 两点到根节点的路径和 减去 他们LCA到根节点的路径和的两倍 。

在线倍增:

 1 #include<stdio.h>
 2 #include<string.h>
 3 #include<algorithm>
 4 using namespace std;
 5 
 6 const int maxn=4e4+5;
 7 const int maxm=8e4+5;
 8 const int maxl=20;        //总点数的log范围,一般会开稍大一点
 9 
10 int fa[maxl][maxn],dep[maxn],dis[maxn];        //fa[i][j]是j点向上(不包括自己)2**i 层的父节点,dep是某个点的深度(根节点深度为0),dis是节点到根节点的距离
11 int head[maxn],point[maxm],nxt[maxm],val[maxm],size,n;
12 
13 void init(){
14     size=0;
15     memset(head,-1,sizeof(head));
16 }
17 
18 void add(int a,int b,int v){
19     point[size]=b;
20     val[size]=v;
21     nxt[size]=head[a];
22     head[a]=size++;
23     point[size]=a;
24     val[size]=v;
25     nxt[size]=head[b];
26     head[b]=size++;
27 }
28 
29 void Dfs(int s,int pre,int d){        //传入当前节点标号,父亲节点标号,以及当前深度
30     fa[0][s]=pre;                    //当前节点的上一层父节点是传入的父节点标号
31     dep[s]=d;
32     for(int i=head[s];~i;i=nxt[i]){
33         int j=point[i];
34         if(j==pre)continue;
35         dis[j]=dis[s]+val[i];
36         Dfs(j,s,d+1);
37     }
38 }
39 
40 void Pre(){
41     dis[1]=0;
42     Dfs(1,-1,0);
43     for(int k=0;k+1<maxl;++k){        //类似RMQ的做法,处理出点向上2的幂次的祖先。
44         for(int v=1;v<=n;++v){
45             if(fa[k][v]<0)fa[k+1][v]=-1;
46             else fa[k+1][v]=fa[k][fa[k][v]];    //处理出两倍距离的祖先
47         }
48     }
49 }
50 
51 int Lca(int u,int v){
52     if(dep[u]>dep[v])swap(u,v);        //定u为靠近根的点
53     for(int k=maxl-1;k>=0;--k){
54         if((dep[v]-dep[u])&(1<<k))    //根据层数差值的二进制向上找v的父亲
55             v=fa[k][v];
56     }
57     if(u==v)return u;                //u为v的根
58     for(int k=maxl-1;k>=0;--k){
59         if(fa[k][u]!=fa[k][v]){        //保持在相等层数,同时上爬寻找相同父节点
60             u=fa[k][u];
61             v=fa[k][v];
62         }
63     }
64     return fa[0][u];                //u离lca只差一步
65 }
66 
67 int main(){
68     int T;
69     scanf("%d",&T);
70     while(T--){
71         int m;
72         scanf("%d%d",&n,&m);
73         init();
74         for(int i=1;i<n;++i){
75             int a,b,v;
76             scanf("%d%d%d",&a,&b,&v);
77             add(a,b,v);
78         }
79         Pre();
80         while(m--){
81             int a,b;
82             scanf("%d%d",&a,&b);
83             int num=Lca(a,b);
84             printf("%d\n",dis[a]+dis[b]-2*dis[num]);
85         }
86     }
87     return 0;
88 }
View Code

 

离线Tarjan:

 1 #include<stdio.h>
 2 #include<string.h>
 3 #include<vector>
 4 #include<algorithm>
 5 using namespace std;
 6 
 7 const int maxn=4e4+5;
 8 const int maxm=8e4+5;
 9 const int maxq=205;
10 
11 int n;
12 int head[maxn],nxt[maxm],point[maxm],val[maxm],size;
13 int vis[maxn],fa[maxn],dis[maxn];
14 int ans[maxq];
15 vector<pair<int,int> >v[maxn];
16 
17 void init(){
18     memset(head,-1,sizeof(head));
19     size=0;
20     memset(vis,0,sizeof(vis));
21     for(int i=1;i<=n;++i){
22         v[i].clear();
23         fa[i]=i;
24     }
25     dis[1]=0;
26 }
27 
28 void add(int a,int b,int v){
29     point[size]=b;
30     val[size]=v;
31     nxt[size]=head[a];
32     head[a]=size++;
33     point[size]=a;
34     val[size]=v;
35     nxt[size]=head[b];
36     head[b]=size++;
37 }
38 
39 int find(int x){
40     return x==fa[x]?x:fa[x]=find(fa[x]);
41 }
42 
43 void Tarjan(int s,int pre){
44     for(int i=head[s];~i;i=nxt[i]){
45         int j=point[i];
46         if(j!=pre){
47             dis[j]=dis[s]+val[i];
48             Tarjan(j,s);
49             int x=find(j),y=find(s);
50             if(x!=y)fa[x]=y;
51         }
52     }
53     vis[s]=1;
54     for(int i=0;i<v[s].size();++i){
55         int j=v[s][i].first;
56         if(vis[j]){
57             int lca=find(j);
58             int id=v[s][i].second;
59             ans[id]=dis[s]+dis[j]-2*dis[lca];
60         }
61     }
62 }
63 
64 int main(){
65     int T;
66     scanf("%d",&T);
67     while(T--){
68         int k;
69         scanf("%d%d",&n,&k);
70         init();
71         for(int i=1;i<n;++i){
72             int a,b,v;
73             scanf("%d%d%d",&a,&b,&v);
74             add(a,b,v);
75         }
76         for(int i=1;i<=k;++i){
77             int a,b;
78             scanf("%d%d",&a,&b);
79             v[a].push_back(make_pair(b,i));
80             v[b].push_back(make_pair(a,i));
81         }
82         Tarjan(1,0);
83         for(int i=1;i<=k;++i)printf("%d\n",ans[i]);
84     }
85 }
View Code