LCT学习笔记
来源:互联网 发布:centos 7 3306端口 编辑:程序博客网 时间:2024/06/05 06:03
动态树问题:
动态加边,删边,始终保持是一棵或多棵树。
支持换根,修改点、边、路径权值(等信息),查询路径权值等。
思想:把树分成若干个部分维护。和树链剖分相似,树链剖分的一些题目也可以用LCT来做。LCT的均摊复杂度是log²n,杨哲的论文(百度搜一下,%大神)有证明,但我太弱,看不懂,也不想研究……
一些定义:
access(x) :访问x,这个操作是LCT关键;
Preferred child(更喜欢的儿子~?):一个点P,设P点子树中最近被访问的节点为x,那么x为P点的Prefferred child,如果最后访问P本身,那么P没有Prefferred child。x与P之间的边为Preferred edge,由Preferred edge组成的不可延长的路径叫做Preferred path,与树链剖分的重链差不多。
这样就有一些性质,所有点都在且仅在一个Prefferred path中。所有的Prefferred path包含了这棵树所有点。
access(10);access(13);access(7);access(4);树就变成了这样(图片丑)。
这样的每棵splay我们称为Auxiliary tree(辅助树),每个Auxiliary tree的根节点保存这个Auxiliary tree与上一棵Auxiliary tree中的哪个点相连。这个点称作他的Path parent。
像上图中5的Path parent为2;Path parent相当于儿子认爹,爹不认儿子;由2号点我无法找到5号点。
树链剖分的树是静态的,所以用线段树.树状数组搞,但这是动态树,所以对于每一条Prefferred path,以距离根的距离为关键字,用Splay(Treap应该也可以)维护,深度小的在左儿子,深度大的在右儿子。
主要操作:
access(X):首先由于preferred path的定义,如果一个点被访问,那么这个点到根节点的所有的边都会变成preferred edge,由于每个点只有一个preferred child,所以这个点到根节点路径上的所有的点都会和原来的preferred child断开,连接到这条新的preferred path上。假设访问X点(6号点),那么先将X点旋转到对应Auxiliary tree的根节点,然后因为被访问的点是没有preferred child的,所以将Auxiliary tree中根节点(X)与右子树(10)的边断掉,左节点(3)保留,将这个树的path parent(1)旋转到对应Auxiliary tree的根节点,断掉右子树(2,4),连接这个点(1)与X(6)点,相当于合并两棵Auxiliary tree,不断地重复这一操作,直到当前X所在Auxiliary tree的path parent为null时停止,表示已经完成当前操作。
inline void access(int x){ for(int t=0;x;t=x,x=fa[x]) splay(x),ch[x][1]=t,up(x);}
这样就有一些神奇的事情。
access(x);splay(x);
这时候X为他所在Auxiliary tree的根节点,并且没有右子树;
既然这样,我把这棵树所有左右子树都翻转过来,不就表示以x为根的树了吗.
inline void make_root(int x){access(x);splay(x);rev[x]^=1;}
打了标记之后,每一次Splay都要把这个点以及上面所有祖先标记释放。
stack<int> S;inline void splay(int x){ S.push(x); for(int i=x;!isroot(i);i=fa[i]) S.push(fa[i]); while(!S.empty()) { int v=S.top(); S.pop();pushdown(v); } ………………}
inline void pushdown(int x){ if(rev[x]) { rev[ch[x][0]]^=1; rev[ch[x][1]]^=1; swap(ch[x][0],ch[x][1]); rev[x]=0; }}
link(x,y) x,y之间建边。
inline void link(int u,int v){make_root(u);fa[u]=v;}
cut(x,y)删除x,y之间的边。
先把x作为根,然后access(y);找到x,y之间路径(一条边),splay(y);由于x为根,深度最小,所以x在y的左儿子;
inline void cut(int x,int y){ make_root(x);access(y);splay(y); ch[y][0]=fa[x]=0,up(y);}
find(x);找x的根;
inline int find(int x){ access(x);splay(x); while(ch[x][0]) x=ch[x][0]; return x;}
我去终于写完了。
感谢dqs学长的博客讲解。以及学习过程中抄的fqk,yzy大神的模板。
感谢各种资料……
http://blog.csdn.net/loi_dqs
http://blog.csdn.net/Phenix_2015
http://blog.csdn.net/ws_yzy
话说我不会博客加友链啊。
还有我很弱,这东西才学了一天,大家不要被我误导。
- LCT学习笔记
- LCT学习笔记
- LCT学习笔记
- lct学习笔记
- LCT学习笔记
- LCT ——学习笔记
- 【动态树问题】LCT学习笔记
- Link Cut Tree(LCT )学习笔记
- LCT(Link-Cut-Tree)学习笔记
- LCT学习笔记(不断更新ing)
- LCT(Link Cut Tree)动态树学习笔记
- SPOJ 375 LCT学习
- LCT学习总结
- lct学习小记
- HYSBZ 2243 染色 LCT学习
- LCT动态树学习小记
- LCT
- LCT
- Vue 初接触实战之账单组件
- vsftpd 安装配置(基于Ubuntu)
- html禁止清除input文本输入缓存的两种方法
- MFC radio button 设置默认选中
- 大学学习JAVA C#等用到的单词
- LCT学习笔记
- UIViewController的生命周期及iOS程序执行顺序
- CDC::RoundRect
- c#面试1(填空题)
- Linux 网络编程之ioctl函数
- 数据结构-线性表(List)1
- Chrome导致Browser无法保存page/没有浏览记录/无法增加书签
- C++命名空间
- Android布局文件的命名空间