51nod2621 树上距离一题四解ST表+倍增+Tarjan+树剖

Posted noobimp

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了51nod2621 树上距离一题四解ST表+倍增+Tarjan+树剖相关的知识,希望对你有一定的参考价值。

LCA裸题 只有代码无原理,给自己复习用

1. ST表(这题2^10就够了)

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 
 4 const int maxn=2e3+50;
 5 
 6 int cnt,dfn[maxn],dep[maxn],dp[maxn][21],lg2[maxn],dis[maxn],w[maxn][maxn];
 7 std::vector<int> G[maxn];
 8 void dfs(int u,int fa){
 9     dis[u]=dis[fa]+w[u][fa];
10     dfn[u]=++cnt; dep[u]=dep[fa]+1; dp[cnt][0]=u;
11     for(int i=0,v;i<G[u].size();i++){
12         if((v=G[u][i])==fa) continue;
13         dfs(v,u);
14         dp[++cnt][0]=u;
15     }
16 }
17 void st(){
18     for(int i=2;i<=cnt;i++) lg2[i]=lg2[i>>1]+1;
19     for(int j=1;j<=20;j++){
20         for(int i=1;i+(1<<j)-1<=cnt;i++){
21             int r=i+(1<<(j-1));
22             dp[i][j] = dep[dp[i][j - 1]] < dep[dp[r][j - 1]] ? dp[i][j - 1] : dp[r][j - 1];
23         }
24     }
25 }
26 int que(int l,int r){
27     if(l>r) swap(l,r);
28     int k=lg2[r-l+1];
29     return dep[dp[l][k]] < dep[dp[r - (1 << k) + 1][k]] ? dp[l][k] : dp[r - (1 << k) + 1][k];
30 }
31 int main(){
32     int n,q; cin>>n>>q;
33     for(int i=1;i<n;i++){
34         int u,v,we; cin>>u>>v>>we;
35         G[u].push_back(v);
36         G[v].push_back(u);
37         w[u][v]=w[v][u]=we;
38     }
39     dfs(1,0); st();
40     for(int i=0;i<q;i++){
41         int u,v; cin>>u>>v;
42         printf("%d
",dis[u]+dis[v]-2*dis[que(dfn[u],dfn[v])]);
43     }
44     return 0;
45 }

2. 倍增

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 
 4 const int maxn=2e3+50;
 5 vector<int> G[maxn];
 6 int dep[maxn],fa[maxn][13],dis[maxn],w[maxn][maxn],lim=11;
 7 void dfs(int u,int rt){
 8     dep[u]=dep[rt]+1; fa[u][0]=rt; dis[u]=dis[rt]+w[rt][u];
 9     for(int i=1;i<lim;i++) fa[u][i]=fa[fa[u][i-1]][i-1];
10     for(int i=0;i<G[u].size();i++){
11         int v=G[u][i]; if(v!=rt) dfs(v,u);
12     }
13 }
14 
15 int LCA(int x,int y){
16     if(dep[x]<dep[y]) swap(x,y);//x更深
17     for(int i=lim-1;~i;i--)//x上移
18         if(dep[x]-(1<<i)>=dep[y]) x=fa[x][i];
19     if(x==y) return x;
20     for(int i=lim-1;~i;i--)
21         if(fa[x][i]!=fa[y][i])
22             x=fa[x][i], y=fa[y][i];
23     return fa[x][0];
24 }
25 int main(){
26     ios::sync_with_stdio(0);
27     cin.tie(0); cout.tie(0);
28     int n,q; cin>>n>>q;
29     for(int i=1;i<n;i++){
30         int u,v,we; cin>>u>>v>>we;
31         G[u].push_back(v);
32         G[v].push_back(u);
33         w[u][v]=w[v][u]=we;
34     }
35     dfs(1,0);
36     for(int i=0;i<q;i++){
37         int u,v; cin>>u>>v;
38         int lca=LCA(u,v);
39         cout<<dis[u]+dis[v]-2*dis[lca]<<endl;
40     }
41     
42     return 0;
43 }

3. tarjan

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 
 4 const int maxn=2e3+50;
 5 struct node{ int next,to; }edge[maxn];
 6 int head[maxn],cnt;
 7 void add(int u,int v){
 8     edge[++cnt].to = v;
 9     edge[cnt].next = head[u];
10     head[u] = cnt;
11 }
12 
13 struct node2{ int id,to,next; }que[maxn];
14 int qhead[maxn],cnt2;
15 void add_q(int u,int v,int i){
16     que[++cnt2].to = v;
17     que[cnt2].id = i;
18     que[cnt2].next = qhead[u];
19     qhead[u] = cnt2;
20 }
21 
22 int fa[maxn],lca[maxn],w[maxn][maxn],dis[maxn],ans[maxn];
23 bool vis[maxn];
24 
25 int findd(int x){ return x==fa[x]?x:fa[x]=findd(fa[x]); }
26 
27 void tarjan(int u){
28     vis[u] = 1;
29     for(int i = head[u];i;i = edge[i].next){
30         int v = edge[i].to; if(v==u) continue;
31         if(!vis[v]){                                        //如果没有被访问过,就tagjan这个点
32             dis[v]=dis[u]+w[u][v];
33             tarjan(v);
34             fa[v] =findd(u);
35         }
36     }
37     for(int i = qhead[u];i;i = que[i].next){
38         int v = que[i].to; if(v==u) continue;
39         if(vis[v]){                                          //找答案时,已经访问过的节点就可以记录lca了
40             lca[que[i].id] = findd(v);
41             ans[que[i].id]=dis[u]+dis[v]-2*dis[lca[que[i].id]];        
42            }
43     }
44 }
45 int rt[maxn];
46 int main(){
47     int n,m; cin >> n >> m ;
48     int a,b,we;
49     for(int i = 1;i < n;i ++){
50         cin >> a >> b>>we;
51         add(a,b);
52         add(b,a);
53         w[a][b]=w[b][a]=we;
54     }
55     for(int i = 1;i <= m;i ++){
56         cin >> a >> b;
57         add_q(a,b,i);
58         add_q(b,a,i);
59     }
60     for(int i = 1;i <= n;i ++) fa[i] = i;
61     tarjan(1);
62     for(int i = 1;i <= m;i ++){ cout<<ans[i]<<endl; }
63     return 0;
64 }

4. 树剖

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 
 4 const int maxn=2e3+50;
 5 int cnt, size[maxn], f[maxn], dep[maxn], dis[maxn], w[maxn][maxn], son[maxn], top[maxn];
 6 std::vector<int> G[maxn];
 7 void dfs1(int u,int fa){
 8     size[u]=1; dep[u]=dep[fa]+1; f[u]=fa;
 9     dis[u]=dis[fa]+w[fa][u];
10     for(int i=0;i<G[u].size();i++){
11         int v=G[u][i]; if(v==fa) continue;
12         dfs1(v,u);
13         size[u]+=size[v];
14         if(size[v]>size[son[u]]) son[u]=v;
15     }
16 }
17 
18 void dfs2(int u,int t){
19     top[u]=t;
20     if(son[u]) dfs2(son[u],t);
21     for(int i=0;i<G[u].size();i++){
22         int v=G[u][i];
23         if(v!=f[u]&&v!=son[u]) dfs2(v,v);
24     }
25 }
26 
27 int LCA(int x,int y){
28     while(top[x]!=top[y]){
29         if(dep[top[x]]>dep[top[y]]) x=f[top[x]];
30         else y=f[top[y]];
31     }
32     return dep[x]<dep[y]? x: y;
33 }
34 int main(){
35     ios::sync_with_stdio(0);
36     cin.tie(0); cout.tie(0);
37     int n,q; cin>>n>>q;
38     for(int i=1;i<n;i++){
39         int u,v,we; cin>>u>>v>>we;
40         G[u].push_back(v);
41         G[v].push_back(u);
42         w[u][v]=w[v][u]=we;
43     }
44     dfs1(1,1); dfs2(1,1);
45     for(int i=0;i<q;i++){
46         int u,v; cin>>u>>v;
47         int lca=LCA(u,v);
48         cout<<dis[u]+dis[v]-2*dis[lca]<<endl;
49     }
50     return 0;
51 }

 

以上是关于51nod2621 树上距离一题四解ST表+倍增+Tarjan+树剖的主要内容,如果未能解决你的问题,请参考以下文章

[51nod] 1766树上的最远点对 树的直径 树剖LCA+ST表静态查询

51Nod.1766.树上最远点对(树的直径 RMQ 线段树/ST表)

51Nod 1766 树上的最远点对

[51nod 1288]汽油补给(ST表+单调栈)

51Nod1405树上距离和 二次扫描与换根法

HDU2874倍增ST