【转】动态树

news/2024/7/7 16:08:10

动态树是一种“超级数据结构”,它能够维护一个由若干有根树组成的森林,在对数的时间复杂度内支持:

1.查询一个点的父亲

2.查询一个点所在的树的根

3.修改某个节点的权

4.向从某个节点到它所在的树的根的路径上的所有的节点的权增加一个数

5.查询从某个节点到它所在的树的根的路径上的所有的节点的权的最小值

6.把一棵树从某个节点和它的父亲处断开,使其成为两棵树

7.让一棵树的根成为另一棵树的某个节点的儿子,从而合并这两棵树

8.把某棵树的根修改为它的某个节点

9.查询在同一棵树上的两个节点的LCA

*10.修改以某个节点为根的子树的所有节点的权

*11.查询以某个节点为根的子树的所有节点的权的最小值

......

为了简化问题,我们只考虑一个简化版本:不支持10和11操作

百度文库里有关于动态树的论文。其中介绍的比较多的是Link-Cut Tree,它的核心思想是:

把树剖分成若干个链,之后用平衡树去维护维护这些链。

可以选择的平衡树有Splay,或者在树的形态不改变的情况下使用“全局平衡二叉树”(见2007年某人的某论文)。

有了动态树,我们能够做很多事情,例如:

优化网络流(看某些有关费用流的论文吧)

除了这个“正当”用途外,还有各种“不正当用途”:

并查集(不光支持合并,还支持按某种规则分离呢)

LCA(动态的LCA啊)

RMQ(所谓数列就是一个链,所谓链就是一种退化了的树。对每次要操作的区间,先从树上砍下来,操作完之后合并回去)

可并优先队列(所谓队列就是一个链。。。。。。)

如果你不嫌弃常数,如果你有套模板刷题的习惯,那么可以“一切皆动态树”。

代码真的不算很长,也就190行,3.9K(不算很长。。。)

http://cid-354ed8646264d3c4.office.live.com/self.aspx/.Public/DynamicTree.cpp

就是这个:

#include <cstdio>
#include <algorithm>
#define NMax 10000
using namespace std;
struct node{
int key,mn,delta;
int revmark;
node *p,*l,*r;
node(){}
};
struct DynamicTree{
node *nodes;
int N;
static void ini_node(node *p){
p->p=p->l=p->r=NULL;
p->revmark=0;p->delta=0;p->mn=~0u>>2;p->key=~0u>>2;
}
static int isroot(node *p){return !p->p || (p->p->l!=p && p->p->r!=p);}
DynamicTree(int n){
N=n;
nodes=new node[n];
for (int i=0;i<n;i++)ini_node(nodes+i);
}
static void inc(node *p,int d){
p->key+=d;p->mn+=d;p->delta+=d;
}
static void rev(node *p){
swap(p->l,p->r);
p->revmark^=1;
}
static void down(node *p){
if (p->delta){
if (p->l)inc(p->l,p->delta);
if (p->r)inc(p->r,p->delta);
p->delta=0;
}
if (p->revmark){
if (p->l)rev(p->l);
if (p->r)rev(p->r);
p->revmark=0;
}
}
static void update(node *p){
p->mn=p->key;
if (p->l && p->l->mn+p->delta<p->mn)p->mn=p->l->mn+p->delta;
if (p->r && p->r->mn+p->delta<p->mn)p->mn=p->r->mn+p->delta;
}
static void zig(node *p){
node *x=p->p,*y=x->p;
p->p=y;x->p=p;
if (y){
if (x==y->l)y->l=p;
else if (x==y->r)y->r=p;
}
x->l=p->r;if (x->l)x->l->p=x;
p->r=x;
update(x);
update(p);
}
static void zag(node *p){
node *x=p->p,*y=x->p;
p->p=y;x->p=p;
if (y){
if (x==y->l)y->l=p;
else if (x==y->r)y->r=p;
}
x->r=p->l;if (x->r)x->r->p=x;
p->l=x;
update(x);
update(p);
}
static void Splay(node *p){
static node *stack[NMax];
int top=1;
stack[0]=p;
for (node *q=p;!isroot(q);)stack[top++]=(q=q->p);
while (top)down(stack[--top]);
while (!isroot(p)){
node *q=p->p;
if (isroot(q)){
if (q->l==p)zig(p);
else zag(p);
}else{
if (q==q->p->l){
if (p==q->l){
zig(q);zig(p);
}else{
zag(p);zig(p);
}
}else{
if (p==q->r){
zag(q);zag(p);
}else{
zig(p);zag(p);
}
}
}
}
}
static node* head(node *p){
for (down(p);p->l;p=p->l)down(p);
Splay(p);
return p;
}
static node *tail(node *p){
for (down(p);p->r;p=p->r)down(p);
Splay(p);
return p;
}
static node *prev(node *p){
Splay(p);
if (!p->l)return NULL;
node *q=p->l;
for (;q->r;q=q->r)down(q);
Splay(q);
return q;
}
static node *next(node *p){
Splay(p);
if (!p->r)return NULL;
node *q=p->r;
for (;q->l;q=q->l)down(q);
Splay(q);
return q;
}
static node *Expose(node *p){
node *q;
for (q=NULL;p;p=p->p){
Splay(p);
p->r=q;
update(q=p);
}
return q;
}
node *getNode(int id){return id>=0&&id<N?nodes+id:NULL;}
int getId(node *p){return p?p-nodes:-1;}
static int AskMin(node *p){
return Expose(p)->mn;
}
int AskMin(int id){return AskMin(getNode(id));}
static void Increase(node *p,int d){
inc(Expose(p),d);
}
void Increase(int id,int d){Increase(getNode(id),d);}
static void Change(node *p,int a){
Splay(p);
p->key=a;
update(p);
}
void Change(int id,int a){Change(getNode(id),a);}
static void ChangeRoot(node *p){
rev(Expose(p));
}
void ChangeRoot(int id){ChangeRoot(getNode(id));}
static node *getParent(node *p){
Splay(p);
if (p->l)return prev(p);
return p->p;
}
int getParent(int id){return getId(getParent(getNode(id)));}
static node *getRoot(node *p){
return head(Expose(p));
}
int getRoot(int id){return getId(getRoot(getNode(id)));}
static void Merge(node *p,node *q){
Splay(q);
q->p=p;
}
void Merge(int p,int q){Merge(getNode(p),getNode(q));}
static void Cut(node *p){
Splay(p);
if (p->l){
p->l->p=p->p;
p->p=p->l=NULL;
}else p->p=NULL;
}
void Cut(int id){Cut(getNode(id));}
static node *LCA(node *p,node *q){
node *x=head(Expose(p));
node *y=Expose(q),*z=head(y);
if (x==z)return y;
return NULL;
}
int LCA(int p,int q){return getId(LCA(getNode(p),getNode(q)));}
};
int main()
{
return 0;
}


转载于:https://www.cnblogs.com/c4isr/archive/2012/06/09/2542912.html


http://www.niftyadmin.cn/n/4235267.html

相关文章

(转)java之用volatile和不用volatile的区别

在当前的Java内存模型下&#xff0c;线程可以把变量保存在本地内存&#xff08;比如机器的寄存器&#xff09;中&#xff0c;而不是直接在主存中进行读写。这就可能造成一个线程在主存中修改了一个变量的值&#xff0c;而另外一个线程还继续使用它在寄存器中的变量值的拷贝&…

hyperv虚拟机上虚拟机的cpu个数问题

虚拟机支持的内存容量最多达64G&#xff0c;虚拟机支持的vcpu个数最多为4个&#xff08;如果你虚拟机是WIN2008最多可以4个&#xff0c;如果是win2003最多2个&#xff08;这里其实是表示微软支持的个数&#xff0c;你也可以通过别的技术手段可以支持4个&#xff09;&#xff0c…

(转)为什么volatile不能保证原子性而Atomic可以?

在上篇《非阻塞同步算法与CAS(Compare and Swap)无锁算法》中讲到在Java中long赋值不是原子操作&#xff0c;因为先写32位&#xff0c;再写后32位&#xff0c;分两步操作&#xff0c;而AtomicLong赋值是原子操作&#xff0c;为什么&#xff1f;为什么volatile能替代简单的锁&am…

杂文语录积累(二)

1.不要说什么不想谈&#xff0c;没感觉就是硬道理&#xff1b; 2.没有放不下的事&#xff0c;只有放不下的人&#xff1b; 3.我们不可能在一起一辈子&#xff0c;但我们可以把在一起变的久一点。 4.一直记得一句话&#xff1a;打电话的时候记得微笑&#xff0c;对方听得见。可是…

(转)ConcurrentHashMap分段与锁的学习总结

现阶段的学习策略是理解和实践这些知识点&#xff0c;并没有深入分析其原理&#xff0c;但确实精读了许多关于这个主题基础性的资料让我很受益&#xff08;见参考资料&#xff09;。 哈希表基础 1.哈希表是基于数组的数据结构 2.通过对关键字的哈希运算实现元素的快速定位 3.哈…

[转]JDK Logging深入分析

2019独角兽企业重金招聘Python工程师标准>>> 日志输出是所有系统必备的&#xff0c;很多开发人员可能因为常常使用log4j而忽视了JDK logging模块&#xff0c;两者之间是否有联系&#xff1f;是怎样的联系&#xff1f;JDK logging处理细节是怎么样的&#xff1f;本周…

CAP理论以及Eventually Consistent (最终一致性)解析(转)

1 CAP理论简介10年前&#xff0c;Eric Brewer教授指出了著名的CAP理论&#xff0c;后来Seth Gilbert 和 Nancy lynch两人证明了CAP理论的正确性。CAP&#xff08;Consistency,Availability,partition tolerance)理论告诉我们&#xff0c;一个分布式系统不可能满足一致性&#x…

[转载] 大道至简:软件工程实践者的思想——第七章 从编程到工程

作者&#xff1a;周爱民 来源&#xff1a;http://blog.csdn.net/aimingoo 转载于:https://www.cnblogs.com/6DAN_HUST/archive/2012/06/15/2551519.html