关于动态树
动态树(
解决动态树问题有很多种方法 ,这里介绍
动态树的主体思想和树链剖分很相似(树链剖分戳这里),非常频繁地运用到了
无关内容:
还有一种动态树叫做Euler-Tour Trees,能够实现对子树的某些操作,然而我并没有找到有任何关于它的中文文献。。。
所以等到我哪天英文达到了那个水平再去学吧。。。。
关于
Link
-
Cut
Trees
介绍
定义一些神奇的称呼:
-
access(x) :访问节点x -
PreferredChild :如果结点v 的子树中, 最后被访问的结点在子树w 中, 这里w 是v 的儿子, 那么就称w 是v 的PreferredChild -
PreferredEdge :每个点到它的PreferredChild 的边称作PreferredEdge -
PreferredPath :由PreferredEdge 连接成的不可再延伸的路径称为PreferredPath
其中
容易得出整棵树就被划分成了若干条
access(x)
操作
一旦我们调用
具体操作:
首先,我们将节点
然后,如果点
重复以上操作,直到到达包含根结点的
给出几张图片,方便大家更好地理解
有了
find
_
root(x)
操作
找到节点
具体操作:
先
cut(x)
操作
断开
具体操作:
先
join(v,w)
操作
让
具体操作:
先访问
具体代码
struct LCT {
int fa[MAXN], ch[MAXN][2], data[MAXN], pathparent[MAXN], pn;
void init(int n) {
pn = n;
memset(fa, 0, sizeof(fa));
memset(ch, 0, sizeof(ch));
}
void Rotate(int p, bool t) {
int f = fa[p];
fa[ch[f][t^1] = ch[p][t]] = f;
fa[ch[fa[f]][ch[fa[f]][1]==f] = p] = fa[f];
ch[fa[f] = p][t] = f;
}
void splay(int x) {
int p;
while(fa[x]) {
p = fa[x];
if(!fa[p]) {
Rotate(x, x==ch[p][0]);
break;
}
bool f = x==ch[p][0], f1 = p==ch[fa[p]][0], f2 = p==ch[fa[p]][1];
Rotate(f?f1?p:x:f2?p:x, f);
Rotate(x, f1);
}
}
void access(int v) {
int u = v;
v = 0;
while(u) {
splay(u);
pathparent[ch[u][1]] = u;
ch[u][1] = v;
pathparent[v] = 0;
v = u;
u = pathparent[u];
}
}
int find_root(int v) {
access(v);
splay(v);
while(ch[v][0]) v = ch[c][0];
splay(v);
return v;
}
void cut(int v) {
access(v);
ch[v][0] = 0;
}
void join(int v, int w) {
access(v);
pathparent[v] = w;
access(v);
}
};
我们发现,当一个节点u位于所在的
struct LCT {
bool root[MAXN];
int fa[MAXN], ch[MAXN][2];
void init() {
memset(fa, 0, sizeof(fa));
memset(ch, 0, sizeof(ch));
memset(root, true, sizeof(root));
}
void Rotate(int p, bool t) {
int f = fa[p];
fa[ch[f][t^1] = ch[p][t]] = f;
if(!root[f]) ch[fa[f]][ch[fa[f]][1]==f] = p;
else root[p] = !(root[f] = false);
fa[p] = fa[f];
ch[fa[f] = p][t] = f;
}
void splay(int x) {
while(!root[x]) {
int p = fa[x];
if(root[p]) {
Rotate(x, x==ch[p][0]);
break;
}
bool f = x==ch[p][0], f1 = p==ch[fa[p]][0], f2 = p==ch[fa[p]][1];
Rotate(f?f1?p:x:f2?p:x, f);
Rotate(x, f1);
}
}
void access(int u) {
int v = 0;
while(u) {
splay(u);
root[ch[u][1]] = !(root[v] = false);
ch[u][1] = v;
u = fa[v = u];
}
}
int find_root(int v) {
access(v);
splay(v);
while(ch[v][0]) v = ch[v][0];
splay(v);
return v;
}
void cut(int v) {
access(v);
splay(v);
root[ch[v][0]] = true;
ch[v][0] = fa[ch[v][0]] = 0;
}
void join(int v, int w) {
access(v);
fa[v] = w;
access(v);
}
};
以下是裸题:
HNOI2010 bounce 弹飞绵羊 题目戳这里 题解戳这里
SDOI2008 cave 洞穴勘测 题目戳这里
HDU4010 Query on The Trees 题目戳这里
SPOJ00913 Query on a tree II 题目戳这里