Hdu4010 query on the trees (LCT)

Source: Internet
Author: User

The first dynamic tree in life, in order to understand its general principles, requires some pre-skills, such as the concepts of the splay tree and tree link splitting. Here I will write some experiences when reading various papers. The following code is a copy of the CLJ template. Templates written by others are reliable and easy to learn and understand, then, I learned some papers about some concepts. The following content can be seen as my understanding of others' templates and my experiences on the paper.

LCT supports operations on a tree path, such as querying the sum of vertex weights on the path between U and V, querying the maximum vertex weights, and adding a number to all vertex weights, set it to a tree. Unlike tree link partitioning, it supports splitting the edge of the tree and merging the two trees by connecting one edge. Tree link splitting does not support edge Cutting and edge deletion.

The main method of tree chain partitioning is this. For a tree, we first use DFS to find the duplicate son of each vertex (that is, the one with the most vertices in the Son ), then, we mark these edges as the secondary edges (the remaining are the secondary edges), and then number the secondary edges in the second DFS to achieve continuous duplicate edges with serial numbers. According to certain derivation, we can prove that the Light and Heavy edges from any point to the root path are O (logn)-level. Therefore, when modifying the path, we can use the line tree to maintain the edge, because each edge must be maintained, the cost of updating each edge is logn, so the complexity of a single operation is log ^ 2n.

LCT has the same idea, but because it is dynamic, it requires a more flexible data structure, that is, a dynamic tree. The concept of heavy edge and light edge is also applied or expanded here. The following figure is taken from spoj375 qtree solution.

My understanding of this image is crucial. The LCT defines such an operation as access or expose. After executing access (N), we can find that, all edges in the path from N to the root are changed to the duplicate edge. Because each father has only one duplicate son and only one duplicate edge, the original duplicate edge is changed to the light edge.

In splay, the heavy chains are maintained (only one vertex is a tree), and each heavy chain is a splay tree. For example, the first and second slave databases on the left maintain the following series of splay trees.

Left one: A-B-E; C-G-H-J; I-K; D; F; m

Left 2: A-C-G-H-I-L-N; B-E; D; F; j; k; m; o

In each splay tree, the left subtree points above the current vertex, And the right subtree points below the current vertex. Figure 3 is a description of this, look at the heavy chain of C-G-H-J, the left subtree of G has C, that C is above g, similarly H, J is below G, it corresponds to the left image.

In addition, the relationship between heavy chains needs to be maintained. Therefore, this function is used without adding coarse edges. in the implementation of the splay tree, a fa should be added to each node, it indicates where the parent edge of the heavy chain is.

The next step is to understand the expose operation. Expose (v) needs to hit all vertices from V to the root to the same heavy chain (the same splay tree) for more information about the operation, see the pseudo code in the previous article. For more information, see the pseudo code "dynamic sequence and dynamic tree problem" in this article.

Then there are several typical operation problems. The following is the main content of several typical operations:

(1) Root searching: findroot (u): expose (u), splay (u), while (u-> CH [0]! = NULL) {u = u-> CH [0]} splay (u)

In fact, the path from u to the root is expose, and then splay to the root, because the left subtree points must be at the top, so it keeps walking to the left subtree until it has not been left, then, because it is a splay tree, you have to perform the splay operation again to the root

(2) Root change: makeroot (u): expose (u), splay (u), U-> revit ();

In fact, the path from u to the root is expose, and then u spaly to the root, because after the expose U is completed, there must be no point under U, it is certain that splay (u) after that, U-> CH [1] is empty. In this case, you can flip the u to the root, so there must be a rev mark in the node.

The remaining adding, deleting, querying, and modifying operations are similar. Instead, the path is expose, and the appropriate splay is performed to modify the operation.

Code implementation is similar to splay, but pay special attention to a few points. First, some attributes are added to the node class. For example, isroot indicates whether it is the root, and FA indicates the father of the Light edge. During the rotation, the root should be properly maintained. When the lazy tag is available, a pushto function should be written to upload all the labels from the point to the root.

The code is too long, and there are too many implementation details. It is too scary to write the code without being written into others' templates.

#pragma warning(disable:4996)#include <iostream>#include <cstring>#include <string>#include <cstdio>#include <vector>#include <algorithm>#include <map>using namespace std;#define ll long long#define maxn 350000#define INF 0x3f3f3f3fstruct Node{Node *p, *ch[2];bool rev;ll sum, val;ll mx;ll add;int size;bool isRoot;Node *fa;Node(){sum = 0; val = 0;rev = 0; mx = -INF;add = 0;size = 0;}void setc(Node *c, int d){ch[d] = c;c->p = this;}bool d(){return p->ch[1] == this;}void upd(){sum = ch[0]->sum + ch[1]->sum + val;size = ch[0]->size + ch[1]->size + 1;mx = max(max(ch[0]->mx, ch[1]->mx), val);}void revIt(){rev ^= 1;}void addIt(int vx){add += vx;sum += vx*size;val += vx;mx += vx;}void relax();void setRoot(Node *f);}Tnull, *null = &Tnull;void Node::setRoot(Node *f){fa = f;isRoot = true;p = null;}void Node::relax(){if (add != 0){for (int i = 0; i < 2; i++){if (ch[i] != null) ch[i]->addIt(add);}add = 0;}if (rev){swap(ch[0], ch[1]);for (int i = 0; i < 2; i++){if (ch[i] != null) ch[i]->revIt();}rev = 0;}}Node mem[maxn], *C = mem;Node *make(int v){C->sum = C->val = v;C->rev = 0; C->add = 0;C->mx = v;C->ch[0] = C->ch[1] = null; C->isRoot = true;C->p = null;C->fa = null;return C++;}void rot(Node *t){Node *p = t->p;p->relax();t->relax();bool d = t->d();p->p->setc(t, p->d());p->setc(t->ch[!d], d);t->setc(p, !d);p->upd();if (p->isRoot){p->isRoot = false;t->isRoot = true;t->fa = p->fa;}}void pushTo(Node*t) {static Node*stk[maxn]; int top = 0;while (t != null) {stk[top++] = t;t = t->p;}for (int i = top - 1; i >= 0; --i) stk[i]->relax();}void splay(Node*u, Node*f = null) {pushTo(u);while (u->p != f) {if (u->p->p == f)rot(u);elseu->d() == u->p->d() ? (rot(u->p), rot(u)) : (rot(u), rot(u));}u->upd();}Node *v[maxn];vector<int> E[maxn];int n, nQ;int que[maxn], fa[maxn], qh = 0, qt = 0;int wht[maxn];void bfs(){qh = qt = 0;que[qt++] = 1;fa[1] = -1;while (qh < qt){int u = que[qh++];for (int i = 0; i < E[u].size(); i++){int e = E[u][i];if (e != fa[u]){fa[e] = u;v[e]->fa = v[u];que[qt++] = e;}}}}Node *expose(Node *u){Node *v;for (v = null; u != null; v = u, u = u->fa){splay(u);u->ch[1]->setRoot(u);u->setc(v, 1);v->fa = u;}return v;}void makeRoot(Node *u){expose(u);splay(u);u->revIt();}void addEdge(Node *u, Node *v){makeRoot(v);v->fa = u;}void delEdge(Node *u, Node *v){makeRoot(u);expose(v); splay(u); u->setc(null, 1); u->upd();v->setRoot(null);}void addPath(Node *u, Node *v,int ax){makeRoot(u);expose(v);splay(v);v->addIt(ax);}ll sumPath(Node *u, Node *v){makeRoot(u);expose(v);splay(v);return v->sum;}ll maxPath(Node *u, Node *v){makeRoot(u);expose(v);splay(v);return v->mx;}Node *find_root(Node *u){expose(u); splay(u);while (u->ch[0] != null){u = u->ch[0];}splay(u); return u;}int main(){while (cin >> n){for (int i = 0; i <= n; i++) E[i].clear();int ui, vi;for (int i = 0; i < n - 1; i++){scanf("%d%d", &ui, &vi);E[ui].push_back(vi); E[vi].push_back(ui);}for (int i = 1; i <= n; i++){scanf("%d", wht + i);v[i] = make(wht[i]);}bfs();cin >> nQ;int oper, wi, xi, yi;Node *nx, *ny;while (nQ--){scanf("%d", &oper);if (oper == 3) scanf("%d%d%d", &wi, &xi, &yi);else scanf("%d%d", &xi, &yi);nx = v[xi]; ny = v[yi];if (oper == 1){if (find_root(nx) == find_root(ny)) puts("-1");else{addEdge(nx, ny);}}else if (oper == 2){if (find_root(nx) != find_root(ny) || xi == yi) puts("-1");else{makeRoot(nx);expose(ny);splay(ny);Node *tmp = ny->ch[0];ny->ch[0] = null; ny->upd();tmp->setRoot(null);}}else if (oper == 3){if (find_root(nx) != find_root(ny)) puts("-1");else{addPath(nx, ny, wi);}}else{if (find_root(nx) != find_root(ny)) puts("-1");else printf("%d\n", maxPath(nx, ny));}}puts("");}return 0;}

 

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.