/*
节点的标号从1开始
*/
#include <cstdio>
#include <algorithm>
using namespace std;
const int N = 10000; //N为节点的个数
struct e{
int v;
e* nxt;
}es[N<<1], *fir[N];
struct node{
int ls, rs; //左右儿子的下标,为-1表示空
int l, r; //区间的左右标号
//数据域,根据不同的需要添加,数据的down和update和线段树的无异
int mid() { return (l + r) >> 1; }
}nodes[N<<1];
int n, en;
int que[N], par[N], dep[N], root[N], seg[N], st[N], ed[N], top[N], sons[N], id[N];
//que用于BFS,par记录父节点,dep记录节点的深度。 root[i]为链i的根节点,seg用于在链上建线段树,
//st[i],ed[i]分别为链i的左右端点,top[i]为链i的顶部的节点,sons[i]为节点i的儿子节点
//id[i]是节点i所属的链的标号,
int ln, cnt, tr; //ln是链的个数,cnt为节点的个数,tr是树的根节点
inline void add_e(int u, int v){
es[en].v = v;
es[en].nxt = fir[u];
fir[u] = &es[en++];
}
inline void newNode(int& id, int l, int r){
nodes[cnt].ls = nodes[cnt].rs = -1;
nodes[cnt].l = l;
nodes[cnt].r = r;
id = cnt++;
}
void build(int& id, int l, int r){ //在剖分出来的链上构建线段树
newNode(id, l, r);
if(l >= r){
//seg[l]为落在这个线段树节点上的原树中的节点
return ;
}
int mid = (l+r)>>1;
build(nodes[id].ls, l, mid);
build(nodes[id].rs, mid+1, r);
}
void initTree(){ //初始化剖分树
//确定父亲
int l, r, u, v, i;
e* cur;
l = r = 0;
que[r++] = tr;
par[tr] = -1;
dep[tr] = 0;
while(l != r){
u = que[l++];
int g = 1;
for(cur = fir[u]; cur; cur = cur->nxt){
if((v = cur->v) != par[u]){
que[r++] = v;
par[v] = u;
dep[v] = dep[u]+1;
}
}
}
//计算子树大小
for(i = 1; i <= n; i++){
sons[i] = 1;
id[i] = -1;
}
for(i = r-1; i >= 0; i--){
u = que[i];
if(par[u] >= 0){
sons[par[u]] += sons[u];
}
}
//剖分链
l = r = 0;
que[r++] = tr;
ln = cnt = 0;
while(l != r){
u = que[l++];
st[ln] = dep[u]; //用节点的深度作为线段树中区间的左右标号
top[ln] = u;
while(u >= 0){
id[u] = ln;
ed[ln] = dep[u];
seg[dep[u]] = u;
int best;
for(cur = fir[u], best=-1; cur; cur = cur->nxt){
if(id[v = cur->v] == -1){
if(best == -1 || (best >= 0 && sons[v] > sons[best])){
best = v;
}
}
}
if(best >= 0){
for(cur = fir[u]; cur; cur = cur->nxt){
if(id[v = cur->v] == -1 && best != v){
que[r++] = v;
}
}
}
u = best;
}
root[ln] = -1;
build(root[ln], st[ln], ed[ln]);
ln++;
}
}
void lqry(int& id, int ql, int qr){
if(id == -1) return ;
if(ql <= nodes[id].l && nodes[id].r <= qr){
return ;
}
if(nodes[id].l == nodes[id].r){
return ;
}
int mid = (nodes[id].l+nodes[id].r)>>1;
if(ql <= mid){
lqry(nodes[id].ls, ql, qr);
}
if(qr > mid){
lqry(nodes[id].rs, ql, qr);
}
}
void qry(int u, int v){ //查询u和v之间的最大值
while(id[u] != id[v]){
if(id[u] > id[v]){
swap(u, v);
}
int b = id[v];
lqry(root[b], st[b], dep[v]);
v = par[top[b]];
}
if(dep[u] > dep[v]){
swap(u, v);
}
lqry(root[id[u]], dep[u], dep[v]);
}
int main(){
return 0;
}
分享到:
相关推荐
#include #include #include #define N 30003 #define INF 2147483647 using namespace std; int n,f[N][20],dep[N],siz[N],son[N],top[N],tot,pos[N],w[N]; int Max[N*4],Sum[N*4];...vector <int> to[N];...
#### P3384 【模板】轻重链剖分/树链剖分 **题目概述:** 此题提供了一棵包含`N`个节点的树,每个节点有一个初始值。需要支持以下四种操作: 1. **1 x y z**:将从节点`x`到节点`y`最短路径上的所有节点值加`z`。 2...
ACM-ICPC算法模板1是一种常用的竞赛编程算法模板,涵盖了图论、并查集、最小生成树、Kruskal、堆优化、Prim、Dijkstra、最近公共祖先、RMQ-ST、强连通分量树链剖分等多种算法和数据结构。以下是该模板的详细知识点...
树链剖分是一种将树结构划分为多条链的技术,使得能够利用线段树或其它数据结构对树上路径进行快速查询和修改。在模版中提到了修改边权、查询路径最大边权等应用场景。树链剖分技术结合线段树可以高效地对树上路径...
树链剖分.cpp ---- NOTONLLY的SBT模板.cpp NOTONLLY的划分树模板.cpp NOTONLLY的后缀数组模板.cpp RMQ-ST算法.cpp RMQ线段树.cpp SBT.cpp SBT2.cpp splay伸展树.cpp ST表.cpp Treap.cpp Trie树.cpp 二叉堆.cpp 二维...
树链剖分 52 平衡二叉树 56 Splay 56 数学 64 结论&&推论 64 快速乘法 65 逆元 66 [1, n]素数个数 66 pell方程 68 秦九韶算法 68 求π 69 黑科技 72 求某天是星期几 72 扩栈 73 JAVA 73 builtin函数 74
树链剖分是一种对树结构进行分治优化的方法,它将一棵树分解成若干个链,使得每个节点到根节点的路径上只经过链的顶点。这在处理树上的动态问题时非常有用,例如求解最短路径、LCA(最近公共祖先)等。在给出的代码...
- 树链剖分:一种高效处理树上路径查询问题的算法。 - 生成树计数:计算一个图有多少种不同的生成树。 - 最小边割集:在无向图中找出最小的边割集,即最小化割边的集合,以破坏图的连通性。 - 二分图最小权覆盖集:...
4.最小生成树 5.拓扑排序 6.差分约束 7.倍增求LCA 8.有向图的强联通分量 9.无向图的双联通分量 1.树状数组 2.线段树 3.树链剖分 4.平衡树
- **各种树形数据结构**:如平衡二叉搜索树(Splay)、线段树(Segment Tree)、树链剖分(Tree Chain Split)、替罪羊树等。 - **高级树结构**:如李超线段树、左偏树、二维树状数组等。 - **图论算法**:包括...
包括树剖,线段树,splay,Treap,网络流,RMQ,数论函数求值,主席树,树状数组,LCA,CRT,BSGS,树套树等模板。(注:其中的两个cdq模板都没用的,整体二分写错了,其余模板可以自行测试。 p.s.有些可能与一些已...
树链剖分是一种分割树的技术,能够将一棵树分解为若干条重路径和轻边,从而支持高效的区间查询和更新操作。Link-Cut Tree 是一种支持动态维护树结构的数据结构。 #### 字符串 ##### 后缀数组 后缀数组是一种支持对...
12. 树形结构:包括树链剖分、树的重心、基环树等。 13. 并查集与离散化:数据结构与算法的高效实现方式。 14. 多线程编程:在算法竞赛中,处理大规模数据时可能会涉及多线程编程技巧。 15. 排序与离散化:对数据...
3. **树链剖分**:对树进行分割,简化节点间距离查询和修改操作。 4. **其他未列出的数据结构**:可能包括平衡二叉搜索树、堆、图算法等,用于解决不同类型的问题。 这些算法和数据结构是ACM/ICPC竞赛中常见的工具...
- **三角剖分**: 三角剖分是指将一个点集划分成三角形的过程。 **5. 数值分析** - **数值积分**: 数值积分是求解定积分近似值的方法,包括辛普森法、梯形法则等。 - **插值法**: 插值法是一种根据已知数据点估计...
17. **最近公共祖先**:通过倍增查询或树链剖分等技术来高效地查找二叉树或树结构中节点的最近公共祖先。 18. **最长公共上升子序列**:寻找两个序列中长度最长的公共子序列,且该子序列是递增的。 19. **点分治**...
树链剖分 树的点分治 树的边分治 图论 图的基本结构 强联通分量 无向图求桥 无向图求割点 二分图匹配 匈牙利算法 Hopcroft-Karp算法 二分图最优匹配 KM 算法 最小树形图 朱刘算法 最大密度子图 01分数规划 && 网络流...
树链剖分: with 线段树: String 后缀数组: Geo 凸包: 旋转卡壳: LeetCode 目前只打算做easy和medium中的大部分题目(有些恶心的模拟和锁题不写),偶尔看到拍个板子就能过的hard题也会顺手过一下 模板