题意:有 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
",dis[a]+dis[b]-2*dis[num]);
85 }
86 }
87 return 0;
88 }
离线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
",ans[i]);
84 }
85 }