树链剖分入门

我学的学习资料: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 }

 

posted @ 2016-05-20 20:44  Recoder  阅读(451)  评论(0编辑  收藏  举报