Tarjan之求LCA
Tarjan之求LCA
不要问我为什么写完Tarjan还要再补一句“求LCA的那个”
因为只说Tarjan的话完全不知道你指的是哪个算法……
劳模Tarjan同志证明了好多算法,而且全都叫Tarjan算法(是不会起名了吗x)
这个Tarjan是一个求LCA的离线算法
关于什么是在线什么是离线……
“所谓的在线算法就是实时性的,比方说,给你一个输入,算法就给出一个输出,就像是http请求,请求网页
一样。给一个实时的请求,就返回给你一个请求的网页。而离线算法则是要求一次性读入所有的请求,然后在
统一处理。而在处理的过程中不一定是按照请求的输入顺序来处理的。说不定后输入的请求在算法的执行过程
中是被先处理的。”
↑从网上抄来的w↑感觉很好懂……
因为是离线做法,重新排列了一下解决询问的顺序,所以要比在线算法快
Tarjan的前置技能是dfs和并查集,不会的赶紧去学x
那么正片开始!
因为这是个离线算法,所以读进来各条边之后继续读进来所有询问并存起来
然后从根开始dfs
访问到每个点的时候,先遍历从这个点u出去的所有边,dfs未访问过的点v,访问后把这个点并到u的并查集上
然后扫一遍和u有关的所有询问及其涉及到的点v
如果点v已经被访问过了,那么说明u和v的LCA已经算好了
真相只有一个,LCA就是点v所在的并查集的祖先
赶紧存进答案数组里……
全部dfs完成后,答案也全部算完了,按询问序输出答案就OK了
具体实现可以看代码OvO
//Tarjan lca #include<iostream> #include<cstdio> using namespace std; const int N=500009; int n,m,s,cnt,tot,ep[N],qp[N],fa[N]; bool vis[N]; struct edge{ int to,nex; }e[N<<1]; struct query{ int to,nex,ans; }q[N<<1]; int read() { int an=0; char ch=getchar(); while(!('0'<=ch&&ch<='9'))ch=getchar(); while('0'<=ch&&ch<='9'){an=an*10+ch-'0';ch=getchar();} return an; } int found(int x) { if(x==fa[x])return x; return fa[x]=found(fa[x]); } void adde(int u,int v) { ++cnt; e[cnt].to=v; e[cnt].nex=ep[u]; ep[u]=cnt; } void addq(int u,int v) { ++tot; q[tot].to=v; q[tot].nex=qp[u]; qp[u]=tot; } void dfs(int u) { vis[u]=1;fa[u]=u; for(int i=ep[u];i;i=e[i].nex) { int v=e[i].to; if(!vis[v]){dfs(v);fa[v]=u;} } for(int i=qp[u];i;i=q[i].nex) { int v=q[i].to; if(vis[v]) { q[i].ans=found(v); if(i&1)q[i+1].ans=q[i].ans; else q[i-1].ans=q[i].ans; } } } int main() { n=read(),m=read(),s=read(); for(int i=1;i<n;++i) { int x=read(),y=read(); adde(x,y);adde(y,x); } for(int i=1;i<=m;++i) { int x=read(),y=read(); addq(x,y);addq(y,x); } dfs(s); for(int i=1;i<=m;++i) printf("%d\n",q[i<<1].ans); return 0; }
偷着放一份s菌的代码
#include<iostream> #include<cstdio> #include<cstdlib> #include<queue> #include<algorithm> using namespace std; int read(){ int an=0,f=1;char ch=getchar(); while(!('0'<=ch&&ch<='9')){if(ch=='-')f=-f;ch=getchar();} while('0'<=ch&&ch<='9'){an=an*10+ch-'0';ch=getchar();} return an*f; } int n,m,s,cnt,qf[500099],f[500099],fa[500099],ans[500099<<1]; int x,y; bool vis[500099]; int found(int x){ if(fa[x]!=x)fa[x]=found(fa[x]); return fa[x];} struct saber{ int to,nex; }b[500099<<1]; struct question{ int to,nex; }qu[500099<<1]; void add(int x,int y){ cnt++;b[cnt].to=y; b[cnt].nex=f[x];f[x]=cnt; } void add(int x,int y,int z){ qu[z].to=y; qu[z].nex=qf[x]; qf[x]=z; } void dfs(int x){ fa[x]=x;vis[x]=1;//cout<<x<<" "; for(int i=f[x];i;i=b[i].nex){ int v=b[i].to; if(!vis[v]){ dfs(v); fa[v]=x; } } for(int i=qf[x];i;i=qu[i].nex){ int v=qu[i].to; if(vis[v]){ ans[i]=found(v); if(i&1)ans[i+1]=ans[i]; else ans[i-1]=ans[i]; } } } int main(){ n=read();m=read();s=read(); for(int i=1;i<n;i++){ int x,y;x=read();y=read(); add(x,y);add(y,x); } for(int i=1;i<=m;i++){ x=read();y=read(); add(x,y,i*2-1);add(y,x,i*2); } dfs(s); for(int i=1;i<=m;i++){ cout<<ans[2*i]<<endl;} return 0; }
by:wypx