动态树~LCT总结
2013-06-26 20:28
176 查看
这是我开的一套动态树专题:http://acm.hust.edu.cn/vjudge/contest/view.action?cid=25242#overview
首先说一下什么是动态树。动态树可以维护一个动态的森林,支持树的合并(两棵合并成一棵),分离(把某个点和它父亲点分开),动态LCA,树上的点权和边权维护、查询(单点或者树上的一条路径),换根。
这里首先推荐杨哲的集训队作业:http://wenku.baidu.com/view/75906f160b4e767f5acfcedb 这里面对动态树的基本操作介绍比较全面,同时还带有相关证明。
看完论文以后,这里以HDOJ4010为例对LCT作个说明。
本题有四种操作:
1、如果x和y不在同一棵树上则在xy连边
2、如果x和y在同一棵树上并且x!=y则把x换为树根并把y和y的父亲分离
3、如果x和y在同一棵树上则x到y的路径上所有的点权值+w
4、如果x和y在同一棵树上则输出x到y路径上的最大值
非法则输出-1
根据YZ的作业,access是所有动态树所有操作的基础,一次access(u)操作会把从点u到根上的所有点按深度用一棵splay维护,左边比根深度小,右边比根大,那么要提取x到y的路径只要把x换成根再access(y)就可以,换根操作可以先access(x),splay(x)再把整棵splay翻转,因为splay(x)以后在splay上x的右子树是空的,翻转以后x就是深度最小的点,也就是根,这里的翻转可以打懒惰标记,同样,维护链上的和、极值也可以用同样的方法维护。
这样的话所有操作就是先access,再splay,打标记【没了
首先说一下什么是动态树。动态树可以维护一个动态的森林,支持树的合并(两棵合并成一棵),分离(把某个点和它父亲点分开),动态LCA,树上的点权和边权维护、查询(单点或者树上的一条路径),换根。
这里首先推荐杨哲的集训队作业:http://wenku.baidu.com/view/75906f160b4e767f5acfcedb 这里面对动态树的基本操作介绍比较全面,同时还带有相关证明。
看完论文以后,这里以HDOJ4010为例对LCT作个说明。
本题有四种操作:
1、如果x和y不在同一棵树上则在xy连边
2、如果x和y在同一棵树上并且x!=y则把x换为树根并把y和y的父亲分离
3、如果x和y在同一棵树上则x到y的路径上所有的点权值+w
4、如果x和y在同一棵树上则输出x到y路径上的最大值
非法则输出-1
根据YZ的作业,access是所有动态树所有操作的基础,一次access(u)操作会把从点u到根上的所有点按深度用一棵splay维护,左边比根深度小,右边比根大,那么要提取x到y的路径只要把x换成根再access(y)就可以,换根操作可以先access(x),splay(x)再把整棵splay翻转,因为splay(x)以后在splay上x的右子树是空的,翻转以后x就是深度最小的点,也就是根,这里的翻转可以打懒惰标记,同样,维护链上的和、极值也可以用同样的方法维护。
这样的话所有操作就是先access,再splay,打标记【没了
#include <cstdio> #include <iostream> using namespace std; #define N 300010 #define INF (1<<30) struct node { node *p,*ch[2]; int mx,rev,val,add; }nodes ,*cur,*null; int n,m,u,v,w; node *newnode(int key) { cur->p=cur->ch[0]=cur->ch[1]=null; cur->mx=cur->val=key; cur->rev=0; return cur++; } void init() { null=nodes; null->p=null->ch[0]=null->ch[1]=null; null->mx=null->val=-INF; null->add=0; null->rev=0; cur=nodes+1; } struct dynamictree { bool isroot(node *x)//判根 { return x==null || x->p->ch[0]!=x && x->p->ch[1]!=x; } void pushup(node *x) { x->mx=max(x->val,max(x->ch[0]->mx,x->ch[1]->mx)); } void pushdown(node *x) { if(x==null) return; if(x->rev) { x->rev=0; if(x->ch[0]!=null) x->ch[0]->rev^=1; if(x->ch[1]!=null) x->ch[1]->rev^=1; swap(x->ch[0],x->ch[1]); } if(x->add) { if(x->ch[0]!=null) x->ch[0]->add+=x->add,x->ch[0]->val+=x->add,x->ch[0]->mx+=x->add; if(x->ch[1]!=null) x->ch[1]->add+=x->add,x->ch[1]->val+=x->add,x->ch[1]->mx+=x->add; x->add=0; } } void rotate(node *x,int f) { if(isroot(x)) return; node *y=x->p; y->ch[!f]=x->ch[f]; x->p=y->p; if(x->ch[f]!=null) x->ch[f]->p=y; if(y!=null) { if(y==y->p->ch[1]) y->p->ch[1]=x; else if(y==y->p->ch[0]) y->p->ch[0]=x; } x->ch[f]=y; y->p=x; pushup(y); } void splay(node *x) { static node *sta ; int top=1; sta[0]=x; for(node *y=x;!isroot(y);y=y->p) sta[top++]=y->p; while (top) pushdown(sta[--top]); while (!isroot(x)) { node *y=x->p; if(isroot(y)) rotate(x,x==y->ch[0]); else { int f=y->p->ch[0]==y; if(y->ch[f]==x) rotate(x,!f); else rotate(y,f); rotate(x,f); } } pushup(x); } node *access(node *u) { node *v=null; while (u!=null) { splay(u); v->p=u; u->ch[1]=v; pushup(u); v=u; u=u->p; } return v; } node *link(node *u,node *v)//合并 { access(u); splay(u); u->rev=1; u->p=v; } node *cut(node *u)//分离 { access(u); splay(u); u->ch[0]=u->ch[0]->p=null; pushup(u); } void changeroot(node *u)//换根 { access(u)->rev^=1; } node *getroot(node *u)//找根 { access(u); splay(u); while (u->p!=null) u=u->p; splay(u); return u; } bool queryuv(node *u,node *v)//判断是否在同一子树 { while (u->p!=null) u=u->p; while (v->p!=null) v=v->p; return u==v; } }splay; int eu ,ev ; int main () { while (scanf("%d",&n)!=-1) { init(); for(int i=1;i<n;i++) scanf("%d%d",&eu[i],&ev[i]); for(int i=1;i<=n;i++) { int a; scanf("%d",&a); newnode(a); } for(int i=1;i<n;i++) splay.link(nodes+eu[i],nodes+ev[i]); scanf("%d",&m); for(int i=1;i<=m;i++) { scanf("%d",&u); if(u==1) { scanf("%d%d",&u,&v); if(splay.queryuv(nodes+u,nodes+v)) { printf("-1\n"); continue; } splay.link(nodes+u,nodes+v); } else if(u==2) { scanf("%d%d",&u,&v); if(u==v || !splay.queryuv(nodes+u,nodes+v)) { printf("-1\n"); continue; } splay.changeroot(nodes+u); splay.cut(nodes+v); } else if(u==3) { scanf("%d%d%d",&w,&u,&v); if(! splay.queryuv(nodes+u,nodes+v)) { printf("-1\n"); continue; } splay.changeroot(nodes+u); splay.access(nodes+v); node *q=splay.getroot(nodes+v); q->add+=w; q->mx+=w; q->val+=w; } else { scanf("%d%d",&u,&v); if(! splay.queryuv(nodes+u,nodes+v)) { printf("-1\n"); continue; } splay.changeroot(nodes+u); splay.access(nodes+v); printf("%d\n",splay.getroot(nodes+v)->mx); } } printf("\n"); } return 0; }
相关文章推荐
- 动态树LCT总结
- 动态树(LCT)错误总结
- 专题总结:动态树 LCT(Link cut tree)
- [BZOJ2049][SDOI2008]洞穴勘测(动态树LCT)
- Linux下无法加载动态库问题总结
- 动态添加Tab页总结
- 动态规划Dynamic Programming的总结
- ASP.NET MVC 使用总结(二)——扩展HtmlHelper实现动态生成title及meta
- 总结c++的“编译、链接”时引发的血案——动态、静态链接库
- 关于java中子类,父类中,静态代码块: staic{},动态代码块:{},构造方法,类属性,对象属性等执行顺序做个总结:
- MyBatis学习总结(11)——MyBatis动态Sql语句
- 动态规划总结
- [SAP ABAP开发技术总结]反射,动态创建内表、结构、变量
- 0-1背包问题;动态规划;时间复杂度O(n方);给出最大价值与解得情况;内有动态规划思路总结;
- javascript 动态加载 css 方法总结
- [SAP ABAP开发技术总结]动态修改选择屏幕
- bzoj2049-洞穴勘测(动态树lct模板题)
- angular学习总结十一——动态创建组件并实现交互二
- 2017.5.1 java动态代理总结
- ExtJS4.2学习(20)动态数据表格之前几章总结篇1 推荐