動態樹是個好玩的東西
lct題集
splay
樹鏈剖分(好像關係並不大)
先搬dalao部落格
講了這麼多,其實就是維護森林的樹鏈剖分,每一條鏈用splay維護
每乙個splay維護的是一條從上到下按在原樹中深度嚴格遞增的路徑,且中序遍歷splay得到的每個點的深度序列嚴格遞增。
比如有一棵樹,根節點為1(深度1),有兩個兒子2,3(深度2),那麼splay有3種構成方式:,,
,,(每個集合表示乙個splay)
而不能把1,2,3同放在乙個splay中(存在深度相同的點)
每個節點包含且僅包含於乙個splay中
邊分為實邊和虛邊,實邊包含在splay中,而虛邊總是由一棵splay指向另乙個節點(指向該splay中中序遍歷最靠前的點在原樹中的父親)。
因為性質2,當某點在原樹中有多個兒子時,只能向其中乙個兒子拉一條實鏈(只認乙個兒子),而其它兒子是不能在這個splay中的。
那麼為了保持樹的形狀,我們要讓到其它兒子的邊變為虛邊,由對應兒子所屬的splay的根節點的父親指向該點,而從該點並不能直接訪問該兒子(認父不認子)。
打通\(x\)到動態樹的根的路徑(使路徑上的所有點在同乙個splay中)
void access(int x)
使\(x\)變成動態樹的根
void makeroot(int x)
用來判斷連通性(類似並查集)(findroot(x)==findroot(y)表明x,y在同一棵樹中)
inline int findroot(int x)
打通\(x\)到\(y\)的路徑(類似access)
void split(int x, int y)
連線\(x-y\)
void link(int x, int y)
斷開\(x-y\)
void cut(int x, int y)
洛谷p3690 【模板】link cut tree (動態樹)
code
#include#define ll long long
#define rg register
const int n = 300010;
using namespace std;
inline int gi()
struct node t[n];
int s[n], top;
void putrev(int x)
#define pushup(x) (t[x].s = (t[x].v^t[t[x].ch[0]].s^t[t[x].ch[1]].s))
void pushdown(int x)
return ;
}#define get(x) (t[t[x].fa].ch[1]==x)
bool isroot(int x)
void rotate(int x)
void splay(int x)
pushup(x);
return ;
}void access(int x)
void makeroot(int x)
inline int findroot(int x)
void link(int x, int y)
void split(int x, int y)
void cut(int x, int y)
int main()
else if (op == 1) link(x, y);
else if (op == 2) cut(x, y);
else
} return 0;
}
動態樹問題
當一類題目中的樹需要支援換根 加邊 刪邊的這些操作時,會改變樹的形態,並要求維護一些資訊,這類問題稱為動態樹問題。這裡有我寫的學習小記 link cut tree學習小記 支援的功能 換根,加邊,刪邊,鏈上資訊維護。不支援的功能 子樹資訊維護。習題 彈飛綿羊,魔法森林,substring。我不知道真...
動態樹分治
不得不說,樹結構真是巧妙神奇。因為結構簡單,所以變形剖多,在競賽中玩出的花樣也最多。動態樹分治,顧名思義,解決待修改的樹分治問題。原本的樹分治基於邊或者重心的分治可以解決大多數靜態樹鏈問題,但是待修改怎麼辦?其實很簡單,因為樹結構是不變的,就是樹分治的基礎結構不變,對於修改和詢問,只需要在第一次樹分...
動態樹雜談
動態樹,一類用來維護森林連通性的資料結構,主要使用splay來維護偏愛點 邊 preferred child edge 並且通過點在不同splay中的移動提取路徑,或者是修改父子關係以連線或斷開樹邊 動態樹由於其需要動態的修改點 邊關係,所以需要動態的維護點 邊,從而選擇偏愛點 邊而不是像樹鏈剖分中...