Maintain subtree information using link/cut trees
Last Updated :
06 Mar, 2024
Link/Cut Trees is a data structure used in computer science that efficiently maintains a forest of trees under the operations of link (joining two trees into one) and cut (removing an edge to split a tree into two). The Link/Cut Trees data structure is useful in a variety of applications such as in-network flow algorithms, dynamic connectivity, and tree path queries. It has a worst-case time complexity of O(log n) for both link and cut operations, where n is the number of nodes in the tree.
The Link/Cut Tree is a data structure that supports several operations which are discussed below:
- Access(x): This operation makes x the tree’s root and changes the subtree information for all nodes on the path from the current root to x.
- Cut(x): Removes the edge between x and its parent and changes the subtree information for all nodes on the route from the current root to x.
- Link(x, y): This operation creates an edge between x and y, making x the parent of y, and updates the subtree information for all nodes on the route from the current root to x.
To maintain subtree information using Link/Cut trees, we need to perform the following steps:
Step 1: Define a node structure that contains the subtree information and pointers to its parent and children.
C++
struct Node {
int parent, child[2], size, virtual_size;
} nodes[N];
|
Java
class Node {
int parent;
int [] child = new int [ 2 ];
int size;
int virtual_size;
}
|
Python
class Node:
def __init__( self ):
self .parent = 0
self .child = [ 0 , 0 ]
self .size = 0
self .virtual_size = 0
|
C#
class Node {
public int parent;
public int [] child = new int [2];
public int size;
public int virtual_size;
}
|
Javascript
class Node {
constructor() {
this .parent = 0;
this .child = [0, 0];
this .size = 0;
this .virtual_size = 0;
}
}
|
Step 2: Implement the Access(x) operation. To do this, we first call the Splay(x) operation, which makes x the root of the tree. Then, we update the subtree information for all the nodes on the path from the previous root to x.
C++
void access( int x)
{
for ( int y = 0; x; x = nodes[y = x].parent) {
splay(x);
nodes[x].virtual_size -= nodes[y].size;
nodes[x].virtual_size
+= nodes[nodes[x].child[1]].size;
nodes[x].child[1] = y;
pushup(x);
}
}
|
Java
void access( int x) {
for ( int y = 0 ; x != 0 ; x = nodes[y = x].parent) {
splay(x);
nodes[x].virtual_size -= nodes[y].size;
nodes[x].virtual_size += nodes[nodes[x].child[ 1 ]].size;
nodes[x].child[ 1 ] = y;
pushup(x);
}
}
|
C#
void Access( int x)
{
for ( int y = 0; x != 0; x = nodes[y = x].parent)
{
Splay(x);
nodes[x].virtual_size -= nodes[y].size;
nodes[x].virtual_size += nodes[nodes[x].child[1]].size;
nodes[x].child[1] = y;
PushUp(x);
}
}
|
Javascript
function access(x) {
for (let y = 0; x !== 0; x = nodes[y = x].parent) {
splay(x);
nodes[x].virtual_size -= nodes[y].size;
nodes[x].virtual_size += nodes[nodes[x].child[1]].size;
nodes[x].child[1] = y;
pushUp(x);
}
}
|
Python3
def access(x):
y = 0
while x:
y = x
x = nodes[x].parent
splay(y)
nodes[y].virtual_size - = nodes[x].size if x else 0
nodes[y].virtual_size + = nodes[nodes[y].child[ 1 ]].size if nodes[y].child[ 1 ] else 0
nodes[y].child[ 1 ] = x if x else 0
pushup(y)
|
Step 3: Implement the Cut(x) operation. To do this, we first call the Access(x) operation, which makes x the root of the tree. Then, we set the parent of x to null, and update the subtree information for all the nodes on the path from the previous root to x.
C++
void cut( int x)
{
access(x);
splay(x);
if (!nodes[x].child[0]) {
return ;
}
nodes[nodes[x].child[0]].parent = 0;
nodes[x].child[0] = 0;
pushup(x);
}
|
Java
class Node {
int parent;
int [] child = new int [ 2 ];
public Node( int parent, int child0, int child1) {
this .parent = parent;
this .child[ 0 ] = child0;
this .child[ 1 ] = child1;
}
}
class SplayTree {
Node[] nodes;
public SplayTree(Node[] nodes) {
this .nodes = nodes;
}
private void access( int x) {
}
private void splay( int x) {
}
private void pushUp( int x) {
}
public void cut( int x) {
access(x);
splay(x);
if (nodes[x].child[ 0 ] == 0 ) {
return ;
}
nodes[nodes[x].child[ 0 ]].parent = 0 ;
nodes[x].child[ 0 ] = 0 ;
pushUp(x);
}
}
public class Main {
public static void main(String[] args) {
Node[] nodes = new Node[ ];
SplayTree splayTree = new SplayTree(nodes);
int x = ;
splayTree.cut(x);
}
}
|
Python
def cut(x):
access(x)
splay(x)
if nodes[x].child[ 0 ] = = 0 :
return
nodes[nodes[x].child[ 0 ]].parent = 0
nodes[x].child[ 0 ] = 0
push_up(x)
|
C#
void Cut( int x)
{
Access(x);
Splay(x);
if (nodes[x].Child[0] == 0)
{
return ;
}
nodes[nodes[x].Child[0]].Parent = 0;
nodes[x].Child[0] = 0;
PushUp(x);
}
|
Javascript
class Node {
constructor(parent, child0, child1) {
this .parent = parent;
this .child = [child0, child1];
}
}
class SplayTree {
constructor(nodes) {
this .nodes = nodes;
}
access(x) {
}
splay(x) {
}
pushUp(x) {
}
cut(x) {
this .access(x);
this .splay(x);
if ( this .nodes[x].child[0] === 0) {
return ;
}
this .nodes[ this .nodes[x].child[0]].parent = 0;
this .nodes[x].child[0] = 0;
this .pushUp(x);
}
}
const nodes = [];
const splayTree = new SplayTree(nodes);
const x = 0;
splayTree.cut(x);
|
Step 4: Implement the Link(x, y) operation. To do this, we first call the Access(y) operation, which makes y the root of its tree. Then, we call the Access(x) operation, which makes x the root of its tree. Finally, we set the parent of y to x, and update the subtree information for all the nodes on the path from the previous roots of x and y to x.
C++
void link( int x, int y)
{
makeroot(x);
access(y);
splay(y);
nodes[x].parent = y;
nodes[y].virtual_size += nodes[x].size;
}
|
Java
void link( int x, int y) {
makeroot(x);
access(y);
splay(y);
nodes[x].parent = y;
nodes[y].virtual_size += nodes[x].size;
}
|
Python
def link(x, y):
makeroot(x)
access(y)
splay(y)
nodes[x].parent = y
nodes[y].virtual_size + = nodes[x].size
|
C#
void link( int x, int y) {
makeroot(x);
access(y);
splay(y);
nodes[x].parent = y;
nodes[y].virtual_size += nodes[x].size;
}
|
Javascript
function link(x, y) {
makeroot(x);
access(y);
splay(y);
nodes[x].parent = y;
nodes[y].virtual_size += nodes[x].size;
}
|
Here are some codes:
C++
struct Node {
int parent, child[2], size, virtual_size;
} nodes[N];
void access( int x)
{
for ( int y = 0; x; x = nodes[y = x].parent) {
splay(x);
nodes[x].virtual_size -= nodes[y].size;
nodes[x].virtual_size
+= nodes[nodes[x].child[1]].size;
nodes[x].child[1] = y;
pushup(x);
}
}
void link( int x, int y)
{
makeroot(x);
access(y);
splay(y);
nodes[x].parent = y;
nodes[y].virtual_size += nodes[x].size;
}
void cut( int x)
{
access(x);
splay(x);
if (!nodes[x].child[0]) {
return ;
}
nodes[nodes[x].child[0]].parent = 0;
nodes[x].child[0] = 0;
pushup(x);
}
void pushup( int x)
{
nodes[x].size = nodes[nodes[x].child[0]].size
+ nodes[nodes[x].child[1]].size
+ nodes[x].virtual_size + 1;
}
|
Java
class Node {
int parent, child[] = new int [ 2 ], size, virtual_size;
}
class GFG {
Node[] nodes;
public LinkCutTree( int N) {
nodes = new Node[N];
for ( int i = 0 ; i < N; i++) {
nodes[i] = new Node();
nodes[i].parent = nodes[i].child[ 0 ] = nodes[i].child[ 1 ] = 0 ;
nodes[i].size = nodes[i].virtual_size = 1 ;
}
}
void access( int x) {
for ( int y = 0 ; x != 0 ; x = nodes[y = x].parent) {
splay(x);
nodes[x].virtual_size -= nodes[y].size;
nodes[x].virtual_size += nodes[nodes[x].child[ 1 ]].size;
nodes[x].child[ 1 ] = y;
pushup(x);
}
}
void link( int x, int y) {
makeroot(x);
access(y);
splay(y);
nodes[x].parent = y;
nodes[y].virtual_size += nodes[x].size;
}
void cut( int x) {
access(x);
splay(x);
if (nodes[x].child[ 0 ] == 0 ) {
return ;
}
nodes[nodes[x].child[ 0 ]].parent = 0 ;
nodes[x].child[ 0 ] = 0 ;
pushup(x);
}
void pushup( int x) {
nodes[x].size = nodes[nodes[x].child[ 0 ]].size
+ nodes[nodes[x].child[ 1 ]].size
+ nodes[x].virtual_size + 1 ;
}
}
|
C#
class Node
{
public int parent;
public int [] child = new int [2];
public int size;
public int virtual_size;
}
const int N = 10000;
Node[] nodes = new Node[N];
void Access( int x)
{
for ( int y = 0; x != 0; x = nodes[y = x].parent)
{
Splay(x);
nodes[x].virtual_size -= nodes[y].size;
nodes[x].virtual_size += nodes[nodes[x].child[1]].size;
nodes[x].child[1] = y;
PushUp(x);
}
}
void Link( int x, int y)
{
MakeRoot(x);
Access(y);
Splay(y);
nodes[x].parent = y;
nodes[y].virtual_size += nodes[x].size;
}
void Cut( int x)
{
Access(x);
Splay(x);
if (nodes[x].child[0] == 0)
{
return ;
}
nodes[nodes[x].child[0]].parent = 0;
nodes[x].child[0] = 0;
PushUp(x);
}
void PushUp( int x)
{
nodes[x].size = nodes[nodes[x].child[0]].size +
nodes[nodes[x].child[1]].size +
nodes[x].virtual_size + 1;
}
|
Javascript
class Node {
constructor() {
this .parent = 0;
this .child = [0, 0];
this .size = 0;
this .virtual_size = 0;
}
}
const N = 1000;
const nodes = Array.from({ length: N }, () => new Node());
function access(x) {
for (let y = 0; y <= x; y++) {
x = nodes[y].parent;
splay(x);
nodes[x].virtual_size -= nodes[y].size;
nodes[x].virtual_size += nodes[nodes[x].child[1]].size;
nodes[x].child[1] = y;
pushup(x);
}
}
function link(x, y) {
makeroot(x);
access(y);
splay(y);
nodes[x].parent = y;
nodes[y].virtual_size += nodes[x].size;
}
function cut(x) {
access(x);
splay(x);
if (!nodes[x].child[0]) {
return ;
}
nodes[nodes[x].child[0]].parent = 0;
nodes[x].child[0] = 0;
pushup(x);
}
function pushup(x) {
nodes[x].size =
nodes[nodes[x].child[0]].size +
nodes[nodes[x].child[1]].size +
nodes[x].virtual_size +
1;
}
|
Python3
class Node:
def __init__( self ):
self .parent = 0
self .child = [ 0 , 0 ]
self .size = 0
self .virtual_size = 0
N = 1000
nodes = [Node() for _ in range (N)]
def access(x):
for y in range ( 0 , x + 1 ):
x = nodes[y].parent
splay(x)
nodes[x].virtual_size - = nodes[y].size
nodes[x].virtual_size + = nodes[nodes[x].child[ 1 ]].size
nodes[x].child[ 1 ] = y
pushup(x)
def link(x, y):
makeroot(x)
access(y)
splay(y)
nodes[x].parent = y
nodes[y].virtual_size + = nodes[x].size
def cut(x):
access(x)
splay(x)
if not nodes[x].child[ 0 ]:
return
nodes[nodes[x].child[ 0 ]].parent = 0
nodes[x].child[ 0 ] = 0
pushup(x)
def pushup(x):
nodes[x].size = nodes[nodes[x].child[ 0 ]].size + nodes[nodes[x].child[ 1 ]].size + nodes[x].virtual_size + 1
|
Share your thoughts in the comments
Please Login to comment...