LCA的三种求法

来源:互联网 发布:数据库概念模型 图片 编辑:程序博客网 时间:2024/06/05 17:47

Tarjan

一遍 大法师 处理所有询问, 每次递归处理子树, 把子树与当前节点的并查集合并. 然后如果一个询问的两个节点都被访问, 直接输出答案

#include<stdio.h>#include<string.h>#include<vector>using namespace std;int T,n,m,a,b,c,p[40010],vis[40010],dep[40010],ans[210];vector<pair<int,int> >g[40010];vector<pair<int,int> >ask[40010];int find(int x) {return x==p[x]?x:p[x]=find(p[x]);}void Tarjan(int u,int fa,int d) {dep[u]=d;for(int i=0;i<g[u].size();i++) {pair<int,int> &v=g[u][i];if(v.first!=fa) {Tarjan(v.first,u,d+v.second);p[v.first]=find(u);}}vis[u]=1;for(int i=0;i<ask[u].size();i++) {pair<int,int> &v=ask[u][i];if(vis[v.first]) {ans[v.second]=dep[u]+dep[v.first]-2*dep[find(v.first)];}}}int main() {scanf("%d",&T);while(T--) {scanf("%d%d",&n,&m);memset(vis,0,sizeof vis);memset(ans,-1,sizeof ans);for(int i=0;i<=n;i++) {g[i].clear();ask[i].clear();}for(int i=1;i<n;i++) {scanf("%d%d%d",&a,&b,&c);g[a].push_back(make_pair(b,c));g[b].push_back(make_pair(a,c));}for(int i=1;i<=m;i++) {scanf("%d%d",&a,&b);ask[a].push_back(make_pair(b,i));ask[b].push_back(make_pair(a,i));}for(int i=1;i<=n;i++) p[i]=i;Tarjan(1,0,0);for(int i=1;i<=m;i++) {printf("%d\n",ans[i]);}}}

`RMQ 求法 (ST 表)

#include<stdio.h>#include<string.h>#include<vector>#include<algorithm>using namespace std;int T,n,m,a,b,c,time,e[80010],p[40010],dep[40010],dp[22][80010];vector<pair<int,int> >g[40010];void dfs(int u,int fa,int d) {dep[u]=d;p[u]=time;e[time++]=u;for(int i=0;i<g[u].size();i++) {if(g[u][i].first!=fa) {dfs(g[u][i].first,u,d+g[u][i].second);e[time++]=u;}}}void rmq() {for(int i=1;i<2*n;i++) dp[0][i]=e[i];for(int i=1;1<<i<=2*n;i++) {for(int j=1;j<2*n;j++) {dp[i][j]=min(dp[i-1][j],dp[i-1][j+(1<<i-1)]);}}}int getmin(int l,int r) {if(l>r) swap(l,r);int i=0;while((1<<i)<=r-l+1) i++; i--;return min(dp[i][l],dp[i][r-(1<<i)+1]);}int main() {scanf("%d",&T);while(T--) {time=1;memset(e,0,sizeof e);memset(p,0,sizeof p);memset(dp,63,sizeof dp);scanf("%d%d",&n,&m);for(int i=1;i<=n;i++) g[i].clear();for(int i=1;i<n;i++) {scanf("%d%d%d",&a,&b,&c);g[a].push_back(make_pair(b,c));g[b].push_back(make_pair(a,c));}dfs(1,-1,0);rmq();while(m--) {scanf("%d%d",&a,&b);c=getmin(p[a],p[b]);printf("%d\n",dep[a]+dep[b]-2*dep[c]);}}}

倍增

写挂了


原创粉丝点击