Tarjan LCA
GeneralLiu的一篇博客<<<
一个神奇的离线求lca方式 而且看到dfs和并查集就感觉特别亲切
本方式使用链式前向星处理输入的树,并设置一个que[]来表示深搜的时候有没有访问过该点
对于给定的根节点,对它进行如下处理:
1:依次搜索和它相连的子节点,即深搜它的所有子树
2:遍历所有与它相关的节点,即题目要问的xx与它的最近公共祖先
如果xx已经访问过,那么它与xx的最近公共祖先即为find(xx)
如果xx还未访问,则不做任何处理
3:在回溯的时候将它和它的子节点合并
看是不是很棒
luogu有一道lca模板题可以练习这个
放代码
1 #include<iostream> 2 #include<cstdlib> 3 #include<cstdio> 4 #include<cctype> 5 6 long long read(){ 7 long long num=0,f=1; 8 char ch=getchar(); 9 while(!isdigit(ch)){ 10 if(ch=='-') f=-1; 11 ch=getchar(); 12 } 13 while(isdigit(ch)){ 14 num=num*10+ch-'0'; 15 ch=getchar(); 16 } 17 return num*f; 18 } 19 20 21 22 using namespace std; 23 int father[500010]; 24 int head [500010]; 25 int qhead [500010]; 26 int que [500010]; 27 28 struct Edge{ 29 int next,to; 30 }edge[1000010]; 31 32 struct qEdge{ 33 int next,to,ans; 34 qEdge(){ans=0;} 35 }q[1000010]; 36 37 int cnt; 38 void add(int x,int y){ 39 cnt++; 40 edge[cnt].to=y; 41 edge[cnt].next=head[x]; 42 head[x]=cnt; 43 } 44 45 void qadd(int x,int y,int k){ 46 q[k].to=y; 47 q[k].next=qhead[x]; 48 qhead[x]=k; 49 } 50 51 int find(int x){ 52 if(father[x]!=x) father[x]=find(father[x]); 53 return father[x]; 54 } 55 56 void unionn(int x,int y){ 57 x=find(x);y=find(y); 58 father[y]=x; 59 } 60 61 void tarjan(int x){ 62 que[x]=1; 63 for(int i=head[x];i;i=edge[i].next){ 64 int to=edge[i].to; 65 if(!que[to]){ 66 tarjan(to); 67 unionn(x,to); 68 } 69 } 70 for(int i=qhead[x];i;i=q[i].next){ 71 int to=q[i].to; 72 if(que[to]==2){ 73 q[i].ans=find(to); 74 if(i%2) q[i+1].ans=q[i].ans; 75 else q[i-1].ans=q[i].ans; 76 } 77 } 78 que[x]=2; 79 } 80 81 int main(){ 82 int n=read(),m=read(),s=read(); 83 for(int i=1;i<n;++i){ 84 int x=read(),y=read(); 85 add(x,y); 86 add(y,x); 87 father[i]=i; 88 } 89 father[n]=n; 90 for(int i=1;i<=m;++i){ 91 int x=read(),y=read(); 92 qadd(x,y,i*2-1); 93 qadd(y,x,i*2); 94 } 95 tarjan(s); 96 for(int i=1;i<=n;++i){ 97 printf("%d\n",q[i*2].ans); 98 } 99 return 0; 100 }
对了快%%%%%%GeneralLiu