LinkCutTree 总结
2015-02-14 23:09
232 查看
最近学习了LinkCutTree,总结一下。
LinkCutTree是一种数据结构(是Tree Decomposition中的一种),她维护的一般是无向图(一个森林),支持连边、删边、链修改、链查询(点属于特殊的链,修改可以是单点修改、整链修改,查询可以是最值、和等)这四种操作。
中心思想是将边分类,一类边组成一些连续的链,每条链保存在一颗BST中(一般是Splay),BST中以点到根的距离为关键字(左边的点是右边的点的祖先),其它一些边连接这些链。(LinkCutTree是树链剖分(又叫轻重链剖分)的动态版本,并且更灵活),可以证明,LinkCutTree的各种操作都是均摊O(logn)的(渐进复杂度比树链剖分的O(log^2)还好,但是常数巨大,所以实测一般时间是树链剖分的1.5~2倍)。
上面的“链修改、链查询”指的是链上的点,如果要将对象改为边,可以为每条边建立一个边点,即若存在边(u,v),则新加一个点z代表边,将z连接u和v,z的点权就是(u,v)的边权,非边点的权设为-oo),然后对边权的统计就变成了对点权的统计(这是LCT中处理边信息的通法之一)。
View Code
推荐学习资料:
杨思雨 《伸展树的基本操作与应用》
杨哲 《QTREE解法的一些研究》
http://blog.csdn.net/d891320478/article/details/9181385
LinkCutTree是一种数据结构(是Tree Decomposition中的一种),她维护的一般是无向图(一个森林),支持连边、删边、链修改、链查询(点属于特殊的链,修改可以是单点修改、整链修改,查询可以是最值、和等)这四种操作。
中心思想是将边分类,一类边组成一些连续的链,每条链保存在一颗BST中(一般是Splay),BST中以点到根的距离为关键字(左边的点是右边的点的祖先),其它一些边连接这些链。(LinkCutTree是树链剖分(又叫轻重链剖分)的动态版本,并且更灵活),可以证明,LinkCutTree的各种操作都是均摊O(logn)的(渐进复杂度比树链剖分的O(log^2)还好,但是常数巨大,所以实测一般时间是树链剖分的1.5~2倍)。
上面的“链修改、链查询”指的是链上的点,如果要将对象改为边,可以为每条边建立一个边点,即若存在边(u,v),则新加一个点z代表边,将z连接u和v,z的点权就是(u,v)的边权,非边点的权设为-oo),然后对边权的统计就变成了对点权的统计(这是LCT中处理边信息的通法之一)。
#include <cstdio> #include <iostream> #define maxn 10010 using namespace std; /* 我的代码风格:用数组模拟指针和结构体。 变量含义: pnt[u] - path-parent of u in the tree pre[u] - the father of u in the Splay son[u][0] - the left child of u in the Splay son[u][1] - the right child of u in the Splay val[u] - the weight of u sum[u] - the sum of weight of all the nodes in the subtree of u siz[u] - the number of the nodes in the subtree of u itg[u] - increasement tag ( the lazy tag ) rtg[u] - rotate tag ( the lazy tag ) */ /* 模板功能:支持删边和连边,支持将一条链的点权做一个增量,支持查询一条链的点权和,判断两点是否再同一联通块中 因为是自己想的一个功能,所以没有地方交,不保证代码正确性。(重在理解) 代码中哪里不懂欢迎回复,代码丑别喷。 */ namespace L { int pnt[maxn], pre[maxn], son[maxn][2], val[maxn], sum[maxn], siz[maxn], itg[maxn], rtg[maxn]; void update( int nd ) { sum[nd] = val[nd] + sum[son[nd][0]] + sum[son[nd][1]]; } void rotate( int nd, int d ) { int p = pre[nd]; int s = son[nd][!d]; int ss = son[s][d]; son[nd][!d] = ss; son[s][d] = nd; if( p ) son[p][ nd==son[p][1] ] = s; else pnt[s] = pnt[nd]; pre[nd] = s; pre[s] = p; pre[ss] = nd; update( nd ); update( s ); } void pushdown( int nd ) { if( rtg[nd] ) { int &ls = son[nd][0], &rs = son[nd][1]; swap(ls,rs); rtg[ls] ^= 1; rtg[rs] ^= 1; rtg[nd] = 0; } if( itg[nd] ) { int ls = son[nd][0], rs = son[nd][1]; int delta = itg[nd]; itg[ls] += delta; itg[rs] += delta; val[ls] += delta; val[rs] += delta; sum[ls] += siz[ls]*delta; sum[rs] += siz[rs]*delta; itg[nd] = 0; } } void big_push( int nd ) { if( pre[nd] ) big_push(pre[nd]); pushdown(nd); } void splay( int nd, int top=0 ) { big_push(nd); while( pre[nd]!=top ) { int p = pre[nd]; int nl = nd==son[p][0]; if( pre[p]==top ) { rotate( p, nl ); } else { int pp = pre[p]; int pl = p==son[pp][0]; if( nl==pl ) { rotate( pp, pl ); rotate( p, nl ); } else { rotate( p, nl ); rotate( pp, pl ); } } } } void access( int nd ) { int u = nd; int v = 0; while( u ) { splay( u ); int s = son[u][1]; pre[s] = 0; pnt[s] = u; pre[v] = u; son[u][1] = v; update( u ); v = u; u = pnt[u]; } splay( nd ); } int findroot( int nd ) { while( pre[nd] ) nd=pre[nd]; while( pnt[nd] ) { nd = pnt[nd]; while( pre[nd] ) nd=pre[nd]; } return nd; } void makeroot( int nd ) { access( nd ); rtg[nd] ^= 1; } bool sameroot( int u, int v ) { return findroot(u)==findroot(v); } void link( int u, int v ){ makeroot(u); makeroot(v); pnt[u] = v; } void cut( int u, int v ) { makeroot(u); access(v); pnt[u] = 0; pre[u] = 0; son[v][0] = 0; update( v ); } void up_val( int u, int v, int delta ) { makeroot(u); access(v); val[v] += delta; sum[v] += siz[v]*delta; itg[v] += delta; } int qu_sum( int u, int v ) { makeroot(u); access(v); return val[v]+sum[son[v][0]]; } }; /* int main() { L::link(1,2); L::link(2,3); L::link(3,4); L::up_val(1,3,3); L::up_val(2,4,-3); printf( "%d\n", L::qu_sum(1,1) ); printf( "%d\n", L::qu_sum(2,2) ); printf( "%d\n", L::qu_sum(3,3) ); printf( "%d\n", L::qu_sum(4,4) ); printf( "%d\n", L::qu_sum(2,3) ); } */ int main() { L::link(1,2); L::link(2,3); L::link(3,4); L::up_val( 1, 4, 5 ); L::cut(2,3); printf( "%d\n", L::qu_sum(1,2) ); printf( "%d\n", L::qu_sum(3,4) ); printf( "%d\n", L::sameroot(2,3) ); }
View Code
推荐学习资料:
杨思雨 《伸展树的基本操作与应用》
杨哲 《QTREE解法的一些研究》
http://blog.csdn.net/d891320478/article/details/9181385
相关文章推荐
- 【无图慎入】Link Cut Tree 总结
- Link-Cut-Tree总结
- 动态树(Link-Cut-Tree)简单总结(指针版本)
- URAL 题目1553. Caves and Tunnels(Link Cut Tree 修改点权,求两点之间最大)
- 【BZOJ2594】 Wc2006 水管局长数据加强版 Link-Cut-Tree
- BZOJ 2631 tree 动态树(Link-Cut-Tree)
- BZOJ 2049 Sdoi2008 Cave 洞穴勘测 动态树 Link-Cut-Tree
- 2002: [Hnoi2010]Bounce 弹飞绵羊(link-cut-tree)
- HDOJ 题目2475 Box(link cut tree去点找祖先)
- 【BZOJ2049】[Sdoi2008]Cave 洞穴勘测 Link-Cut-Tree
- BZOJ 2555 Substring 后缀自动机+Link-Cut-Tree
- bzoj2002 [Hnoi2010]Bounce 弹飞绵羊 (Link Cut Tree)
- Link Cut Tree (paint)
- bzoj1036 [ZJOI2008]树的统计Count (树链剖分|Link Cut Tree)
- [BZOJ 1036] [ZJOI2008] 树的统计Count 【Link Cut Tree】
- BZOJ 2002 弹飞绵羊 Link-Cut-Tree(LCT)
- bzoj 2049: [Sdoi2008]Cave 洞穴勘测 (link-cut-tree)
- spoj QtreeII(link-cut-tree模板)
- BZOJ 3091 城市旅行 Link-Cut-Tree
- BZOJ2157【Link Cut Tree】