Note

1.DFS1

mark all the depth

mark fathers

mark the heavy/light children

mark the size of each subtree

void dfs1(long long pos, long long f, long long depth){
dep[pos] = depth;
fat[pos] = f;
sz[pos] = 1;
long long maxi = -1;
for (long long v : adj[pos]){
if (v == f) continue;
dfs1(v,pos,depth+1);
sz[pos]+=sz[v];
if (maxi<sz[v]) {maxi = sz[v];son[pos] = v;}
}
}

2.DFS2

mark the of the members in the base array

record the top of each node

traverse heavy son first then light son

mark the heavy son along the path

give the base array a value

record the id of each node

void dfs2(long long pos, long long top_pos){
id[pos] = ++cnt;
wt[cnt] = num[pos];
top[pos] = top_pos;
if (!son[pos]) return;
dfs2(son[pos],top_pos);
for (long long v : adj[pos]){
if (v==fat[pos] || v==son[pos]) continue;
dfs2(v,v);
}
}

3.make_tree

make segment tree base on the base array

void make_tree(int way, int l, int r){
if (l==r) {seg[way] = wt[l]%p;return;}
int mid = (l+r)/2;
make_tree(way*2,l,mid);
make_tree(way*2+1,mid+1,r);
seg[way] = (seg[way*2]+seg[way*2+1])%p;
}
//push function
void push(int way,int lenn){
lazy[way*2]+=lazy[way];
lazy[way*2+1]+=lazy[way];
seg[way*2]+=lazy[way]*(lenn-(lenn>>1));
seg[way*2+1]+=lazy[way]*(lenn>>1);
seg[way*2]%=p;
seg[way*2+1]%=p;
lazy[way]=0;
}

4.query_up

query base on the segment tree

int query_up(int way, int l, int r, int qlow, int qhigh){
push(way,l,r);
if (qlow<= l && r<=qhigh) return seg[way]%p;
if (l>qhigh || r<qlow) return 0; int mid = (l+r)/2;
return (query_up(way*2,l,mid,qlow,qhigh) + query_up(way*2+1,mid+1,r,qlow,qhigh))%p;
}

5.query

1) check if they are on the same chain. if Not, add the distance from a node to the top of the chain, and move up

2) repeat step 1 until they are on the same chain

3) query the distance between the nodes based on the base array

int query(int x, int y){
int ans = 0;
while(top[x]!=top[y]){
if (dep[top[x]]<dep[top[y]]) swap(x,y);
ans = (ans+query_up(1,1,n,id[top[x]],id[x]))%p;
x = fat[top[x]];
}
if (dep[x]>dep[y]) swap(x,y);
ans = (ans + query_up(1,1,n,id[x],id[y]))%p;
return ans;
}

6.query_son

query the id[x] plus its size -1 the subtree of a node is consecutive in the base array

int qSon(int x){
return query_up(1,1,n,id[x],id[x]+sz[x]-1);
}

7.update

update normal segment tree (use id as substitution)

void update(int way, int l, int r, int qlow, int qhigh, int val){
push(way,l,r);
if (qlow<=l && r<=qhigh) {
lazy[way] += val;
push(way,l,r);
return;
}
if (l>qhigh || r<qlow) return;
int mid = (l+r)/2;
update(way*2,l,mid,qlow,qhigh,val);
update(way*2+1,mid+1,r,qlow,qhigh,val);
seg[way] = (seg[way*2]+seg[way*2+1])%p;
}

8.update chain

1) check if they are on the same chain. If not, update the chain, and go to the father of the chain head

2) repeat until they are on the same chain

3) update the id of the nodes on the segment tree

void upPath(int x, int y, int val){
while(top[x]!=top[y]){
if (dep[top[x]]<dep[top[y]]) swap(x,y);
update(1,1,n,id[top[x]],id[x],val);
x = fat[top[x]];
}
if (dep[x]>dep[y]) swap(x,y);
update(1,1,n,id[x],id[y],val);
}

9.update_son

update id[x] plus its size -1

void upSon(int x, int val){
update(1,1,n,id[x],id[x]+sz[x]-1,val);
}

optional: LCA

1) check if the two nodes are on the same chain

2) if not, find the one with a deeper head, move it up

3) repeat until they are in the same chain

3) return the one with higher depth

int LCA (int x , int y ) {
int fx = top[x] , fy = top[y] ;
while(fx!=fy) {
if(level[fx]< level[fy]) swap(x,y) , swap(fx ,fy) ;
x = fat[fx] ; fx = top[x];
}
if( level[x] > level[y] ) swap(x,y) ;
return x ;
}

Note to myself

Segment tree is able to support different data structure

Heavy Light Decomposition的更多相关文章

  1. 树链剖分I 原理

    树链剖分(Heavy Light Decomposition, HLD)是一种将对[树上两点间的路径]上[边或点]的[修改与查询]转化到[序列]上来处理的方法. 目的:将树的边或点转化到一个线性结构( ...

  2. 神奇的树上启发式合并 (dsu on tree)

    参考资料 https://www.cnblogs.com/zhoushuyu/p/9069164.html https://www.cnblogs.com/candy99/p/dsuontree.ht ...

  3. HDU 5111 Alexandra and Two Trees 树链剖分 + 主席树

    题意: 给出两棵树,每棵树的节点都有一个权值. 同一棵树上的节点的权值互不相同,不同树上节点的权值可以相同. 要求回答如下询问: \(u_1 \, v_1 \, u_2 \, v_2\):询问第一棵树 ...

  4. [HNOI2018]毒瘤

    Description 从前有一名毒瘤. 毒瘤最近发现了量产毒瘤题的奥秘.考虑如下类型的数据结构题:给出一个数组,要求支持若干种奇奇怪怪的修改操作(比如区间加一个数,或者区间开平方),并支持询问区间和 ...

  5. Wolfycz的娱乐赛题解

    现在不会放题解的!比赛完了我会把题解放上来的 祝大家玩的愉快~ 等会,cnblogs不会显示更新时间?我禁赛我自己 UPD:2018.12.15 欢迎大家爆踩标程- painting 我们考虑转化题意 ...

  6. [ZJOI2011]道馆之战

    Description 口袋妖怪(又名神奇宝贝或宠物小精灵)红/蓝/绿宝石中的水系道馆需要经过三个冰地才能到达馆主的面前,冰地中的每一个冰块都只能经过一次.当一个冰地上的所有冰块都被经过之后,到下一个 ...

  7. codechef Heavy-light Decompositions

    Heavy-light Decompositions Problem Code: HLDOTSSubmit All submissions for this problem are available ...

  8. ACM/ICPC 之 拓扑排序-反向(POJ3687)

    难点依旧是题意....需要反向构图+去重+看题 POJ3687-Labeling Balls 题意:1-N编号的球,输出满足给定约束的按原编号排列的重量序列,如果有多组答案,则输出编号最小的Ball重 ...

  9. poj1013

    题目大意:假造的银币 Sally Jones有一些游客给的银币,但是只有11枚是真正的银币(有一枚是假的),从颜色和大小是无法区分真比还是假币的,但是它的重量和真币是不同的,Sally Jones它是 ...

随机推荐

  1. HDU 4862 JUMP 最小费用最大流

    2014 多校的B题,由于我不怎么搞图论,当时碰到这个题目,我怎么想都没往网络流方面弄,不过网络流真的是个好东西,对于状态多变,无法用动规或者数据结构来很好表示的时候,非常有用 这个题目要求每个点一定 ...

  2. OIer常见问题与错误总结

    作为一名OIer,无论是一名刚入门的蒟蒻,还是叱诧风云的神犇,相信都会难免去犯一些错误(废话不犯错误岂不是都满分了(ノへ ̄.).在这里总结了一些OIer常见易犯的错误,与大家共勉. 1.正常错误 可能 ...

  3. Flink 历史服务与连接器

    History Server(历史服务) Flink提供了记录历史任务运行情况的服务,可用于在关闭Flink群集后依然能够查询已完成作业的相关信息. 配置: # 任务执行信息存储在hdfs目录 job ...

  4. 第十四篇Django-model进阶(中介模型,查询优化,extra,整体插入)

    Django-model进阶(中介模型,查询优化,extra,整体插入) 阅读目录(Content) 中介模型 查询优化 extra 整体插入 中介模型 处理类似搭配 pizza 和 topping ...

  5. mac安装vue没有使用权限不足

    ➜  ~ vue init webpack frontend ⠋ downloading template /usr/local/lib/node_modules/vue-cli/node_modul ...

  6. POJ 2481:Cows 树状数组

    Cows Time Limit: 3000MS   Memory Limit: 65536K Total Submissions: 14906   Accepted: 4941 Description ...

  7. Java算法练习——字符串转换整数 (atoi)

    题目链接 题目描述 请你来实现一个 atoi 函数,使其能将字符串转换成整数. 首先,该函数会根据需要丢弃无用的开头空格字符,直到寻找到第一个非空格的字符为止. 当我们寻找到的第一个非空字符为正或者负 ...

  8. python--多线程的应用

    python 多线程执行函数,以及调用函数时传参 import threading def func1(): print('this is function1') def func2(x,y): pr ...

  9. leetcode - 两数之和Ⅳ 输入BST(653)

    题目描述:给定一个二叉搜索树和一个目标结果,如果 BST 中存在两个元素且它们的和等于给定的目标结果,则返回 true. 解题思路:根据二叉搜索树的特点,对二叉搜索树进行中序遍历可以得到一个从小到达排 ...

  10. 吴裕雄--天生自然JAVA SPRING框架开发学习笔记:Spring DI(依赖注入)的实现方式属性注入和构造注入

    依赖注入(Dependency Injection,DI)和控制反转含义相同,它们是从两个角度描述的同一个概念. 当某个 Java 实例需要另一个 Java 实例时,传统的方法是由调用者创建被调用者的 ...