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表静态查询