-
Notifications
You must be signed in to change notification settings - Fork 809
Link Cut Tree #124
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Link Cut Tree #124
Changes from 7 commits
e6aa29b
2d00e3b
805cc15
1a03c46
7887f5e
1c30800
93f1be2
06b3bd5
5dc6f51
0216a13
6fbfd26
673c2cc
613a162
1fdda13
e95227d
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,116 @@ | ||
/** | ||
* Author: | ||
* Description: link-cut Tree. Supports BBST-like | ||
* augmentations. (Can be used in place of HLD). | ||
* Current implementation supports update value at a node, | ||
* and query max on a path. | ||
* Tested on: http://acm.timus.ru/problem.aspx?num=1553 | ||
* Status: Passes existing fuzz tests (with function names modified). | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We'll want to remove the old link-cut tree, so feel free to do that and modify the fuzz-test. Will also need to update the test to verify that max works (with max replaced by some non-commutative, non-associative function) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Updated the fuzz-test to verify max for now. Will update it later for any new function that we decide on... |
||
*/ | ||
struct Node { | ||
bool flip = 0; | ||
Node *pp, *p, *c[2]; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. is it possible to add a one-line comment explaining what p and pp are? or are they standard names? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. p = parent, pp = path-parent (and c = children). There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. So something like |
||
// add stuff | ||
int val, cval; | ||
PotatoHashing marked this conversation as resolved.
Show resolved
Hide resolved
|
||
Node() { | ||
pp = p = c[0] = c[1] = 0; | ||
val = cval = 0; | ||
} | ||
// lazy propogation | ||
PotatoHashing marked this conversation as resolved.
Show resolved
Hide resolved
|
||
void push() { | ||
if (flip) { | ||
if(c[0]) c[0]->flip ^= 1; | ||
if(c[1]) c[1]->flip ^= 1; | ||
PotatoHashing marked this conversation as resolved.
Show resolved
Hide resolved
|
||
swap(c[0], c[1]); flip = 0; | ||
} | ||
// add stuff | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. remove this comment as well -- I think we can instead write in the description how to augment it ("extend push/pull"). We'll also want a more thorough explanation and/or example -- it's not clear to me in which ways the LCT is similar to a segment tree. E.g. how do I do lazy updates on entire paths in the tree? Entire subtrees? Queries on subtrees? Can I use the flip bit myself for anything? How are things ordered? It's not reasonable to answer all of these questions (we should have a link in the description!), but some more info would be useful. |
||
} | ||
// combine values from children with self. | ||
void pull() { | ||
cval = val; | ||
if(c[0]) c[0]->push(), cval = max(cval, c[0]->cval); | ||
if(c[1]) c[1]->push(), cval = max(cval, c[1]->cval); | ||
// add stuff | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Does this work with non-commutative and non-associative operations? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We've talked about this elsewhere, but it should work for non-commutative, associative functions (like a segment tree). |
||
} | ||
void rot(bool t) { /// start-hash | ||
PotatoHashing marked this conversation as resolved.
Show resolved
Hide resolved
|
||
Node *y = p, *z = y->p; | ||
if (z) z->c[z->c[1] == y] = this; | ||
p = z; | ||
y->c[t] = c[!t]; | ||
if (c[!t]) c[!t]->p = y; | ||
c[!t] = y; | ||
y->p = this; | ||
if (z) z->pull(); | ||
y->pull(); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this is an unreadable mess, it wouldn't hurt to golf it a bit and make it even more unreadable... some ideas:
Also, I'm a bit surprised the pull for z happens before that of y, I would have expected the other way around. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
I might be misunderstanding, but why *&w instead of *w?
Like the fix function in the previous lct? (Set a node's children, and then fix will set those children's parents, but without the "(+ update sum of subtree elements etc. if wanted)" part, since that is what pull does). Pull for z was unnecessary. (A node is only moved up one level for each call of rot, and then pulls up itself at the end of splay.) Thanks for noticing. Everything else seems good. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. oh, I confused
Yeah. I don't know much about how the previous lct works, but it seems like a method along those lines may be able to cut away a few lines? Again, I'm just throwing ideas out, I don't know whether it actually does save anything. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Doesn't look like adding fix will shorten it since |
||
} /// end-hash | ||
void xiao() { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I agree that we should probably rename this There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. "propogatePathParent" is a little much though... Will keep thinking about possible alternatives. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. could certainly shorten that to |
||
if (p) p->xiao(), pp = p->pp; | ||
push(); | ||
} | ||
void splay() { /// start-hash | ||
xiao(); | ||
Node *y, *z; | ||
while (p) { | ||
y = p; z = y->p; | ||
PotatoHashing marked this conversation as resolved.
Show resolved
Hide resolved
|
||
bool t1 = (y->c[1] == this); | ||
if (z) { | ||
bool t2 = (z->c[1] == y); | ||
if (t1 == t2) y->rot(t2), rot(t1); | ||
else rot(t1), rot(t2); | ||
} else rot(t1); | ||
PotatoHashing marked this conversation as resolved.
Show resolved
Hide resolved
|
||
} | ||
pull(); | ||
} /// end-hash | ||
Node* access() {/// start-hash | ||
for (Node *y = 0, *z = this; z; y = z, z = z->pp) { | ||
z->splay(); | ||
if (z->c[1]) z->c[1]->pp = z, z->c[1]->p = 0; | ||
z->c[1] = y; | ||
if (y) y->p = z; | ||
z->pull(); | ||
} | ||
splay(); | ||
return this; | ||
} /// end-hash | ||
}; | ||
struct LinkCut { | ||
vector<Node> node; | ||
PotatoHashing marked this conversation as resolved.
Show resolved
Hide resolved
|
||
LinkCut(int N): node(N) {} | ||
PotatoHashing marked this conversation as resolved.
Show resolved
Hide resolved
|
||
Node* makeRoot(int u) { | ||
PotatoHashing marked this conversation as resolved.
Show resolved
Hide resolved
|
||
node[u].access()->flip ^= 1; | ||
return &node[u]; | ||
} | ||
Node* findRoot(int u) { | ||
Node *x = node[u].access(); | ||
while(x->c[0]) x = x->c[0]; | ||
return x; | ||
} | ||
bool cut(int u, int v) { /// start-hash | ||
Node *x = &node[u], *y = &node[v]; | ||
makeRoot(v); | ||
x->access(); | ||
if (x->c[0] != y || y->c[1] != 0) | ||
PotatoHashing marked this conversation as resolved.
Show resolved
Hide resolved
|
||
return false; | ||
x->c[0] = y->p = y->pp = 0; | ||
x->pull(); | ||
return true; | ||
} /// end-hash | ||
bool isConnected(int u, int v) { | ||
return findRoot(u) == findRoot(v); | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. put this function on one line There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Changed, but goes slightly over the line limit now. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hrm, that's no good then... Either revert or change the function names There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. reverted |
||
bool link(int u, int v) { | ||
Node *y = &node[v]; | ||
if (isConnected(u, v)) return false; | ||
makeRoot(u)->pp = y; | ||
return true; | ||
} | ||
// Add c to node u. | ||
void update(int u, int c) { | ||
node[u].access()->val+=c; | ||
PotatoHashing marked this conversation as resolved.
Show resolved
Hide resolved
|
||
} | ||
// Find max on the path from u to v. | ||
ll query(int u, int v) { | ||
PotatoHashing marked this conversation as resolved.
Show resolved
Hide resolved
|
||
makeRoot(v); | ||
return node[u].access()->cval; | ||
} | ||
}; | ||
PotatoHashing marked this conversation as resolved.
Show resolved
Hide resolved
|
Uh oh!
There was an error while loading. Please reload this page.