tarjan求LCA的体会
#include<iostream> #include<cstdio> #include<cstring> #include<vector> #include<algorithm> using namespace std; const int N=500005; int n,m,s,cnt,num;//树的结点个数、询问的个数和树根结点的序号。 struct EDGE{ int v,next; }; struct QUE{ int node,next,id; }; QUE que[N*3]; EDGE e[N*3]; int vis[N],head[N],vhead[N],fa[N],ans[N]; void add_e(int from,int to) { e[++cnt].v=to; e[cnt].next=head[from]; head[from]=cnt; } int find(int x) { if(x==fa[x]) return x; fa[x]=find(fa[x]); return fa[x]; } void add_q(int u,int to,int id_) { que[++num].id=id_; que[num].node=to; que[num].next=vhead[u]; vhead[u]=num; } void tarjan(int s,int from) { for(int i=head[s];i;i=e[i].next) { int v=e[i].v; if(from!=v) tarjan(v,s),fa[v]=s; } for(int i=vhead[s];i;i=que[i].next) { int v=que[i].node; if(!vis[v]) continue; ans[que[i].id]=find(v); } vis[s]=1; } int main() { /*freopen("in.in","r",stdin); freopen("out.txt","w",stdout);*/ scanf("%d%d%d",&n,&m,&s); for(int i=1;i<n;i++) { int u,v; scanf("%d%d",&u,&v); add_e(u,v),add_e(v,u);//不知道u和v深度的大小关系,所以要加两条边 } for(int i=1;i<=n;i++) fa[i]=i; for(int i=1;i<=m;i++) { int u,v; scanf("%d%d",&u,&v); add_q(u,v,i),add_q(v,u,i); } tarjan(s,0); for(int i=1;i<=m;i++) cout<<ans[i]<<endl; return 0; }
①给que也要开结构体,避免o(m)查询;
②不用一个个倒着找最深的祖先,用并查集加路径压缩。
③跑深搜的时候,要记得加上to[i]!=s,因为加入的边都是无向边,不加的话可能会死循环。