树链剖分求LCA
树链剖分中各种数组的作用:
siz[]数组,用来保存以x为根的子树节点个数
top[]数组,用来保存当前节点的所在链的顶端节点
son[]数组,用来保存重儿子
dep[]数组,用来保存当前节点的深度
fa[]数组,用来保存当前节点的父亲
tid[]数组,用来保存树中每个节点剖分后的新编号
rank[]数组,用来保存当前节点在线段树中的位置
树链剖分求LCA据说很快QWQ,反正我在洛谷上评测的时候比倍增整整快了3分之1.
蓝后我们来说怎么用树链剖分求:
1,第一种情况我们要比较的数在一条链上,比如比较3和12,直接返回深度比较小的数就好了
2,第二种情况我们要比较不在一条链上的两个数,比如我们想求一下10和8的LCA,我们只需要比较一下10和8的重链链顶的深度,我们发现竟然一样深,那我们就用比较早发现的10的链顶就好了,我们吧我们要比较的元素变为自己链顶的父亲(这样就可以实现垮链了),所以近下来我们只需要比较3和8就好,我们发现3和8不在一条链上,所以我们比较3和8链顶的深度,发现8的比较深,所以我们把我们要比较的数变成8的链顶的父亲,也就是3,所以这时候我们要比较的数就都在一条链上了,返回深度比较浅的数就好。
今下来是代码环节,我写了洛谷的3379模板题https://www.luogu.org/problem/show?pid=3379#sub
然后我把我ac的代码粘到这里QWQ
1 #include<cstring> 2 #include<iostream> 3 #include<cstdio> 4 using namespace std; 5 #define MAX 1000 6 7 struct NODE{ 8 int point,next; 9 NODE(){next=0;}; 10 }edge[MAX<<1]; 11 12 int N,M,S; 13 int siz[MAX],dep[MAX],son[MAX],fa[MAX]; 14 int top[MAX],tip[MAX],rank[MAX],tim=0; 15 int edgenum=0,link[MAX]; 16 17 void ADD(int a,int b) 18 { 19 edgenum++; 20 edge[edgenum].point=b; 21 edge[edgenum].next=link[a]; 22 link[a]=edgenum; 23 } 24 25 void pt() 26 { 27 for(int i=1;i<=N;i++){ 28 printf("%3d",i); 29 } 30 cout<<endl; 31 for(int i=1;i<=N;i++){ 32 printf("%3d",top[i]); 33 } 34 } 35 36 void DFS(int x,int deep) 37 { 38 siz[x]=1; 39 dep[x]=deep; 40 for(int i=link[x];i;i=edge[i].next){ 41 int v=edge[i].point; 42 if(v!=fa[x]){ 43 fa[v]=x; 44 DFS(v,deep+1); 45 siz[x]+=siz[v]; 46 if(son[x]==-1||siz[v]>siz[son[x]]){ 47 son[x]=v; 48 } 49 } 50 } 51 } 52 53 void DFS2(int x,int tp) 54 { 55 //cout<<"!"; 56 top[x]=tp; 57 tip[x]=++tim; 58 rank[tip[x]]=x; 59 if(son[x]==-1)return ; 60 DFS2(son[x],tp); 61 for(int i=link[x];i;i=edge[i].next){ 62 int v=edge[i].point; 63 if(v!=son[x]&&v!=fa[x]){ 64 DFS2(v,v); 65 } 66 } 67 } 68 69 int LCA(int a,int b) //重点的注释都在这里 70 { 71 while(top[a]!=top[b]){ //如果两个的链顶不相等,我们就把他们往一起靠 72 if(dep[top[a]]>dep[top[b]]) //看那个点的链顶深度大改变那个点 73 a=fa[top[a]]; 74 else 75 b=fa[top[b]]; 76 } 77 return dep[a]>dep[b]?b:a; //返回时要返回深度比较小的数 78 } 79 80 void init() 81 { 82 int a,b; 83 cin>>N>>M>>S; 84 for(int i=1;i<N;i++){ 85 scanf("%d%d%*c",&a,&b); 86 ADD(a,b); 87 ADD(b,a); 88 } 89 memset(son,-1,sizeof(siz)); 90 } 91 92 void work() 93 { 94 int a,b; 95 for(int i=1;i<=M;i++){ 96 scanf("%d%d%*c",&a,&b); 97 printf("%d\n",LCA(a,b)); 98 } 99 } 100 101 int main() 102 { 103 init();//初始化 104 DFS(S,1);//树链剖分。两个dfs就行 105 DFS2(S,S); 106 work(); //输入询问 107 //pt(); 调试函数,复制下来你们也可以用 108 //system("pause"); 109 return 0; 110 }
posted on 2016-11-09 09:32 fuyun_boy 阅读(1408) 评论(0) 编辑 收藏 举报