<学习笔记> 倍增 lca

例题:codevs 2370 小机房的树

简单来说就是给你一个n个点的树,每一条边都有边权。询问有m次,每次给出两个点,求他们之间的最小边权和。
很容易想到用求树上前缀和和lca,先把两个点跳到高度相同的地方,再一直往上跳,直到两个点重合。因为一个点一个点的跳太慢了,所以我们倍增的跳来求lca。

令f[i][j]表示i号点往上跳2^j步的父亲。

则 f[i][j]=f[f[i][j-1]][j-1];

 

这里有两个板子,思想都一样。

板子一

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<algorithm>
 5 #include<cmath>
 6 using namespace std;
 7 
 8 int n,m,u,v,c,cnt;
 9 int sum[50010],deep[50010],fa[50010][30],first[50010],next[100020];
10 struct maple{
11     int f,t,d;
12 }Rode[100020];
13 
14 void build(int f,int t,int d) //注意双向建边
15 {
16     Rode[++cnt]=(maple){f,t,d};
17     next[cnt]=first[f];
18     first[f]=cnt;
19 }
20 void dfs(int f,int t,int d) // dfs处理出树
21 {
22     deep[t]=deep[f]+1;
23     fa[t][0]=f;
24     sum[t]=d;
25     for(int i=first[t];i;i=next[i])
26        if(Rode[i].t!=f)
27           dfs(t,Rode[i].t,d+Rode[i].d); 
28 }
29 void Done()  // 预处理倍增跳的fa
30 {
31     for(int i=1;i<=log2(n);++i) 
32        for(int j=0;j<=n;++j)
33           fa[j][i]=fa[fa[j][i-1]][i-1]; // j往上跳2^i等同于fa[j][i-1]往上跳i-1步,这里与st表有细微区别 
34 }
35 int lca(int x,int y)
36 {
37     if(deep[x]<deep[y]) swap(x,y); //确保x的深度大
38     for(int i=log2(n);i>=0;--i) // 把x跳到与y深度相同的地方
39     {
40         if(deep[fa[x][i]]>=deep[y])
41            x=fa[x][i];
42     }
43     if(x==y) return x;
44     for(int i=log2(n);i>=0;--i)  //一起往上跳
45        if(fa[x][i]!=fa[y][i])
46          x=fa[x][i],y=fa[y][i];
47     return fa[x][0];
48 }
49 int main()
50 {
51     scanf("%d",&n);
52     for(int i=1;i<n;++i)
53     {
54         scanf("%d%d%d",&u,&v,&c);
55         build(u,v,c);
56         build(v,u,c);
57     }
58     dfs(0,0,0);
59     Done();
60     scanf("%d",&m);
61     while(m--)
62     {
63         scanf("%d%d",&u,&v);
64         printf("%d\n",sum[u]+sum[v]-2*sum[lca(u,v)]);
65     }
66     return 0;
67 }

 

板子二

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cmath>
 4 #include<cstring>
 5 #include<algorithm>
 6 using namespace std;
 7 
 8 int n,u,v,c,m;
 9 int first[150010],next[150010],fa[150010][30],deep[150010],cnt;
10 int de[60000];
11 struct maple{
12     int f,t,d;
13 }rode[150010];
14 
15 void done(int f,int t,int v)
16 {
17     fa[t][0]=f;
18     deep[t]=deep[f]+1;
19     de[t]=de[f]+v;
20     for(int i=1;fa[t][i-1];++i)
21        fa[t][i]=fa[fa[t][i-1]][i-1];
22     for(int i=first[t];i!=-1;i=next[i])
23       if(rode[i].t!=f)
24          done(t,rode[i].t,rode[i].d);
25 }
26 void build(int f,int t,int d)
27 {
28     rode[++cnt]=(maple){f,t,d };
29     next[cnt]=first[f];
30     first[f]=cnt;   
31 }
32 int lca(int x,int y)
33 {
34     if(deep[x]<deep[y]) swap(x,y);
35     if(deep[x]>deep[y])
36     {
37         int l=deep[x]-deep[y];
38         for(int i=0;i<=20;++i)
39             if(l>>i&1) 
40               x=fa[x][i];
41     }          
42     if(x==y) return x;
43     for(int i=log2(n);i>=0;--i)
44         if(fa[x][i]!=fa[y][i]) 
45            x=fa[x][i],y=fa[y][i];
46     return fa[x][0];
47 }
48 
49 int main()
50 {
51     memset(next,-1,sizeof(next));
52     memset(first,-1,sizeof(first));
53     scanf("%d",&n);
54     for(int i=1;i<n;++i)
55     {
56         scanf("%d%d%d",&u,&v,&c);
57         build(u,v,c);
58         build(v,u,c);
59     }
60     done(0,0,0);
61     scanf("%d",&m);
62     while(m--)
63     {
64         scanf("%d%d",&u,&v);
65         printf("%d\n",de[u]+de[v]-2*de[lca(u,v)]);
66     }
67     return 0;
68 }

 

posted @ 2017-11-08 16:40  loi_maple  阅读(186)  评论(0编辑  收藏  举报