树链剖分入门
我学的学习资料:http://blog.sina.com.cn/s/blog_6974c8b20100zc61.html 和 ppt
树链剖分可以解决很多问题,辅助一些线段树之类的数据结构可以解决一些树上修改的问题。还可以求LCA,不过复杂度比RMQ实现的LCA多一个log。
下面是树链剖分实现的LCA:
1 const int MAXN = 5e4 + 10; 2 struct data { 3 int to , next , cost; 4 }edge[MAXN << 1]; 5 int head[MAXN] , cnt; 6 int par[MAXN] , dep[MAXN] , top[MAXN] , id[MAXN] , dis[MAXN] , size[MAXN] , son[MAXN]; 7 8 void init() { 9 memset(head , -1 , sizeof(head)); 10 cnt = 0; 11 } 12 13 inline void add(int u , int v , int cost) { 14 edge[cnt].to = v; 15 edge[cnt].next = head[u]; 16 edge[cnt].cost = cost; 17 head[u] = cnt++; 18 } 19 //求size , par , son , dep 20 void dfs_1(int u , int p , int d) { 21 par[u] = p , size[u] = 1 , son[u] = u , dep[u] = d; 22 for(int i = head[u] ; ~i ; i = edge[i].next) { 23 int v = edge[i].to; 24 if(v == p) 25 continue; 26 dis[v] = dis[u] + edge[i].cost; //离根的距离 27 dfs_1(v , u , d + 1); 28 if(size[v] > size[son[u]]) //取重儿子 29 son[u] = v; 30 size[u] += size[v]; 31 } 32 } 33 //求top , id 34 void dfs_2(int u , int p , int t) { //p为父节点 t为链的祖先 35 top[u] = t; //链的祖先 36 id[u] = ++cnt; //点的顺序 37 if(son[u] != u) //重儿子优先 38 dfs_2(son[u] , u , t); 39 for(int i = head[u] ; ~i ; i = edge[i].next) { 40 int v = edge[i].to; 41 if(v == p || v == son[u]) 42 continue; 43 dfs_2(v , u , v); //树链重新开始 44 } 45 } 46 //树链剖分求lca的复杂度是(nlognlogn),建议用RMQ求lca 47 int lca(int u , int v) { 48 int fu = top[u] , fv = top[v]; 49 while(top[u] != top[v]) { //链是否相同,不同就循环 50 if(dep[fu] < dep[fv]) { //比较两个链的深度 51 v = par[fv]; 52 fv = top[fv]; 53 } 54 else { 55 u = par[fu]; 56 fu = top[u]; 57 } 58 } 59 if(dep[u] >= dep[v]) //在相同的链上 60 return v; 61 return u; 62 }