lca 最近公共祖先 倍增
每日一算,公共祖先问题
分类 单根,那么 直接 dfs(root)
#include<bits/stdc++.h> using namespace std; #define LOACL freopen("in","r",stdin);\ freopen("out","w",stdout); #define FOR(i, a, b) for(int i=(a); i<(b); i++) #define REP(i, a, b) for(int i=(a); i<=(b); i++) #define DOWN(i, a, b) for(int i=(a); i>=(b); i--) #define sz 1000100 #define demen 21 int n,m,s,tot,u,v,head[sz],fa[sz][demen],d[sz]; struct node {int t,nxt;}e[sz]; void add(int u,int v) { e[++tot]=(node){v,head[u]},head[u]=tot;} void dfs(int rt,int f) { d[rt] =d[f]+1; fa[rt][0] = f; REP(i,1,20) fa[rt][i] =fa[fa[rt][i-1]][i-1]; for(int i=head[rt];i;i=e[i].nxt) if(e[i].t!=f) dfs(e[i].t,rt); } int lca(int x,int y) { if(d[x]<d[y])swap(x,y); int dre = d[x] - d[y]; DOWN(i,20,0) if((1<<i)&dre) x = fa[x][i]; if(x==y)return x; DOWN(i,20,0) if(fa[x][i]!=fa[y][i]) x = fa[x][i],y=fa[y][i]; return fa[x][0]; } int main() { //LOACL ios::sync_with_stdio(false); cin>>n>>m>>s; REP(i,1,n-1) { cin>>u>>v; add(u,v),add(v,u); } dfs(s,0); REP(i,1,m) { cin>>u>>v; printf("%d\n",lca(u,v)); } return 0; }
多个根 那么就记搜
#include<bits/stdc++.h> using namespace std; #define LOACL freopen("in","r",stdin);\ freopen("out","w",stdout); #define FASTIO ios::sync_with_stdio(false); #define CLR(arr,val) memset(arr,val,sizeof(arr)) #define DBG(x) cout<<(#x)<<"="<<x<<endl #define DBG2(x,y) cout<<(#x)<<"="<<x<<"\t"<<(#y)<<"="<<y<<endl #define DBG3(x,y,z) cout<<(#x)<<"="<<x<<"\t"<<(#y)<<"="<<y<<"\t"<<(#z)<<"="<<z<<endl #define FOR(i, a, b) for(int i=(a); i<(b); i++) #define REP(i, a, b) for(int i=(a); i<=(b); i++) #define DOWN(i, a, b) for(int i=(a); i>=(b); i--) #define INF 999999999 const int sz = 30000*2; int n,m,x,y,z,tot,q; int head[sz],deep[sz],fa[sz],f[sz][21],w[sz][21]; bool vis[sz]; struct node { int u,v,w; }a[sz]; struct edge { int v,nxt,w; }e[sz<<1]; bool cmp(node l ,node r) { return l.w>r.w; } int getf(int x) { if(x!=fa[x])fa[x]=getf(fa[x]); return fa[x]; } void add(int u ,int v,int w ) { e[++tot] =(edge){v,head[u],w},head[u]=tot; e[++tot] =(edge){u,head[v],w},head[v]=tot; } void krusual() { sort(a+1,a+m+1,cmp); REP(i,1,n) fa[i]=i; REP(i,1,m) { if(getf(a[i].u)!=getf(a[i].v)) { fa[getf(a[i].u)] = getf(a[i].v); add(a[i].u,a[i].v,a[i].w); } } } void dfs(int x) { vis[x] = true; for(int i = head[x];i;i=e[i].nxt) { int v = e[i].v; if(vis[v]) continue; deep[v] =deep[x]+1; f[v][0] = x; w[v][0] = e[i].w; dfs(v); } } int lca (int x,int y) { if(getf(x)!=getf(y)) return -1; int ans=INF; if(deep[x]<deep[y])swap(x,y); DOWN(i,20,0) if(deep[f[x][i]]>=deep[y]) { ans=min(ans,w[x][i]); x = f[x][i]; } if(x==y) return ans; DOWN(i,20,0) { if(f[x][i]!=f[y][i]) { ans=min(ans,min(w[x][i],w[y][i])); x=f[x][i],y=f[y][i]; } } ans = min(ans,min(w[x][0],w[y][0])); return ans; } int lca1(int x,int y) { if(getf(x)!=getf(y)) return -1; int ans=INF; if(deep[x]>deep[y]) swap(x,y); DOWN(i,20,0) { if(deep[f[y][i]] >=deep[x]) { ans = min(ans,w[y][i]); y=f[y][i]; } } if(x==y) return ans; DOWN(i,20,0) { if(f[x][i]!=f[y][i]) { ans=min(ans,min(w[x][i],w[y][i])); x=f[x][i],y=f[y][i]; } } ans = min(ans,min(w[x][0],w[y][0])); return ans; } int main() { LOACL FASTIO cin>>n>>m; REP(i,1,m) cin>>a[i].u>>a[i].v>>a[i].w; krusual(); //先 dfs 一下 然后 init lca REP(i,1,n) { if(!vis[i]) { deep[i]=1; dfs(i); f[i][0]=i; w[i][0]=INF; } } // REP(i,1,n) DBG3(i,f[i][0],w[i][0]); REP(j,1,20) REP(i,1,n) { f[i][j] =f[f[i][j-1]][j-1]; w[i][j] =min(w[i][j-1],w[f[i][j-1]][j-1]); } //REP(i,1,n) DBG3( w[i][0],f[i][0], deep[i]); cin>>q; REP(i,1,q) { cin>>x>>y; cout<<lca(x,y)<<endl; } return 0; }
涉及到一个lca(x,y) 这个函数 的注意事项:
需要的 核心跳转 倍增思想,什么意思呢,记得做填那个神奇算法,硬币分包问题吗?
2^i 会产生对2^(i+1) 影响跳转 ,是不是很神奇,一下子就 砍到了 lg(n) 完全符合算法的思维,n===>lgn 的进化.
不摸着石头过河,难道要在温柔乡睡到天昏地暗。