Link-Cut Tree
来源:互联网 发布:javascript分页代码 编辑:程序博客网 时间:2024/06/07 16:17
推荐资料:
《SPOJ375 QTREE 解法的一些研究》by Yang Zhe
《link cut tree》by popoqqq
正文:
LCT 是解决动态树问题的一种数据结构
LCT=树链剖分+splay
LCT利用splay来维护树上的树链,但是树链不能再以size来剖分了,否则树是静态的。
LCT利用Access操作,将需要访问的节点合并成一个splay,再进行操作。
在splay中是以点的深度作为关键字的。
为了更好维护这一堆splay,需要引入一个叫做Auxiliary Tree(辅助树)的东西。
在辅助树中,如果两个节点u,v,u认为v是父亲,而v不认u是儿子,那么v就是一个splay的根,这条边就叫虚边。
所以这就解释了下面Access中为什么只更新父亲节点的儿子信息,而没有更新父亲节点原来Preferred Child的父亲信息(这一点很精妙,仔细体会)。
具体函数
Access(x):这是一切操作的根源,把x到根的路径上的所有点都合成一个splay,方便操作。
make_root(x):将x设为原树的根
make_root(5)就像如图所示:
可以发现,除了5到根的路径上的节点深度发生了翻转,别的节点深度相对关系是不变的,所以在splay上将5到根的路径的所有点翻转一下。
find(x):找到x的根。由于是按深度为关键字,所以把x旋成x所在的splay的根,再一直向左儿子找,没有了左儿子之后这个点就是根。
Link(x,y):连接x,y。先将x旋成原树的根,再把fa[x]设成y(注意x的儿子不用更新,这是一条虚边)。
Cut(x,y):断开x,y的连边。先将x旋成原树的根,再Access(y),Splay(y),于是x在y左儿子,切断。
维护其他x到y路径上的信息,只要make_root(x),Access(y),Splay(y)就好了。
代码
就拿hdu4010 Query on the tree了:
#include<cstdio>#include<cctype>#include<algorithm>using namespace std;const int INF=2000000000;const int M=300005;int n;int tag[M],rev[M],c[M][2],fa[M],mx[M],v[M];struct Edge{ int to,nxt;}edge[M<<1];int T,head[M],stk[M];void init(){ for(int i=0;i<=n;i++) tag[i]=rev[i]=fa[i]=c[i][0]=c[i][1]=0,head[i]=-1; mx[0]=-INF;T=0;}void add_edge(int a,int b){ edge[T]=(Edge){b,head[a]}; head[a]=T++; edge[T]=(Edge){a,head[b]}; head[b]=T++;}void rec(int x,int f){ fa[x]=f; for(int i=head[x];~i;i=edge[i].nxt) if(edge[i].to!=f) rec(edge[i].to,x);}struct Link_Cut_Tree{ bool is_root(int x){ return c[fa[x]][0]!=x&&c[fa[x]][1]!=x; } void push_up(int x){ int l=c[x][0],r=c[x][1]; mx[x]=max(mx[l],mx[r]); mx[x]=max(mx[x],v[x]); } void update(int x,int w){ tag[x]+=w; mx[x]+=w; v[x]+=w; } void push_down(int x){ int l=c[x][0],r=c[x][1]; if(rev[x]){ rev[l]^=1; rev[r]^=1; rev[x]^=1; swap(c[x][0],c[x][1]); } if(tag[x]){ if(l) update(l,tag[x]); if(r) update(r,tag[x]); tag[x]=0; } } void Rotate(int x){ int y=fa[x],z=fa[y],l,r; l=(c[y][1]==x); r=l^1; if(!is_root(y)) c[z][c[z][1]==y]=x; fa[x]=z; fa[y]=x; fa[c[x][r]]=y; c[y][l]=c[x][r]; c[x][r]=y; push_up(y);push_up(x); } void Splay(int x){ int top=0; stk[++top]=x; for(int i=x;!is_root(i);i=fa[i]) stk[++top]=fa[i]; while(top) push_down(stk[top--]); while(!is_root(x)){ int y=fa[x]; int z=fa[y]; if(!is_root(y)){ if(c[y][0]==x^c[z][0]==y) Rotate(x); else Rotate(y); } Rotate(x); } } void solve(int x,int y){ make_root(x); Access(y); Splay(y); } void Access(int x){ for(int t=0;x;t=x,x=fa[x]) Splay(x),c[x][1]=t,push_up(x); } void make_root(int x){ Access(x); Splay(x); rev[x]^=1; } void link(int x,int y){ make_root(x); fa[x]=y; } void cut(int x,int y){ make_root(x); Access(y); Splay(y); c[y][0]=fa[c[y][0]]=0; push_up(y); } int find(int x){ Access(x); Splay(x); while(c[x][0]) x=c[x][0]; return x; } void add(int x,int y,int val){ make_root(x); Access(y); Splay(y); tag[y]+=val; mx[y]+=val; v[y]+=val; }}lct;inline void Rd(int&res){ res=0;char c; while(c=getchar(),!isdigit(c)); do res=(res<<1)+(res<<3)+(c^48); while(c=getchar(),isdigit(c));}int main(){ while(scanf("%d",&n)!=EOF){ init(); for(int i=1;i<n;i++){ int a,b; Rd(a);Rd(b); add_edge(a,b); } for(int i=1;i<=n;i++) Rd(v[i]),mx[i]=v[i]; rec(1,0); int m; scanf("%d",&m); while(m--){ int opt,x,y; Rd(opt);Rd(x);Rd(y); if(opt==1){ if(lct.find(x)==lct.find(y)) puts("-1"); else lct.link(x,y); }else if(opt==2){ if(lct.find(x)!=lct.find(y)||x==y) puts("-1"); else lct.cut(x,y); }else if(opt==3){ int z=x; x=y; Rd(y); if(lct.find(x)!=lct.find(y)) puts("-1"); else lct.add(x,y,z); }else{ if(lct.find(x)!=lct.find(y)) puts("-1"); else{ lct.solve(x,y); printf("%d\n",mx[y]); } } } puts(""); } return 0;}
- 【link-cut tree】
- Link Cut Tree (paint)
- link-cut-tree
- Link-Cut Tree
- Link/cut tree
- BZOJ2157【Link Cut Tree】
- 【笔记】Link-Cut-Tree
- (link-cut tree)
- Link-Cut-Tree总结
- Link/Cut Tree
- Link-Cut-Tree模板
- Link-Cut-Tree讲解
- link-cut tree预习
- A. Link/Cut Tree
- 【学习心得】Link-cut Tree
- Link-Cut Tree
- link-cut-tree小结
- link-cut-tree
- XenServer安装Linux虚拟机系统如何显示图形界面
- struts接受前端传来的参数的时候,无法调式set方法(看不到变量的值)
- Valid Parentheses 合法括号
- mybaits的Mapper动态代理的简单例子(定义类型别名,ResultMap类型的使用)
- <input type='file'> accept属性
- Link-Cut Tree
- 【NOIP2013模拟联考7】数列
- 正则表达式--------grep
- python websocket.WebSocketApp笔记
- 查看OpenGL版本
- 22. Generate Parentheses
- 【BZOJ2751】【codevs1853】容易题,快速幂+逆元
- 初学CentOS——常见小命令
- 阿里音乐预测 之 初探ODPS SQL