• 【模板】LCT


    (LCT) 是解决动态树问题的一种强力的数据结构,这种数据结构维护的是由若干 (splay) 节点构成的森林。
    (LCT) 结构中采用了实链剖分的策略,即:将树边划分为实边和虚边,其中实边指的是 (splay) 节点通过节点中儿子指针相连的边,虚边指的是通过父节点指针相连的边。实边所构成的所有点在同一棵 (splay) 中,虚边连接不同的 (splay)。这样,就将原树的边集划分到了若干 (splay) 中。
    对于 (LCT) 来说,需要明确一些概念,如下:

    • 原树本身可能不连通,即:真正的树本身就是一个森林。
    • (splay) 维护的是每一个联通块中的树的路径
    • (access) 操作的作用是使得当前节点与当前联通块的根节点在同一棵 (splay)
    • (find\_root) 操作是找到当前节点所在的联通块中根节点的编号
    • 单点修改值时,需要将被修改节点旋转到所在 (splay) 的根节点,否则需要像线段树一样修改一条链。
    #include <bits/stdc++.h>
    
    using namespace std;
    
    struct node {
    	node *l, *r, *p;
    	int val, sum, rev;
    	node(int _val) : val(_val), sum(_val) {
    		l = r = p = NULL;
    		rev = 0;	
    	}
    	void unsafe_reverse() {
    		swap(l, r);
    		rev ^= 1;
    	}
    	void pull() {
    		sum = val;
    		if (l != NULL) {
    			l->p = this;
    			sum ^= l->sum;
    		}
    		if (r != NULL) {
    			r->p = this;
    			sum ^= r->sum;
    		}
    	}
    	void push() {
    		if (rev) {
    			if (l != NULL) {
    				l->unsafe_reverse();
    			}
    			if (r != NULL) {
    				r->unsafe_reverse();
    			}
    			rev = 0;
    		}
    	}
    };
    bool is_root(node *v) {
    	return v->p == NULL || (v->p->l != v && v->p->r != v);
    }
    void rotate(node *v) {
    	node *u = v->p;
    	assert(u != NULL);
    	v->p = u->p;
    	if (v->p != NULL) {
    		if (v->p->l == u) {
    			v->p->l = v;
    		}
    		if (v->p->r == u) {
    			v->p->r = v;
    		}
    	}
    	if (v == u->r) {
    		u->r = v->l;
    		v->l = u;
    	}
    	if (v == u->l) {
    		u->l = v->r;
    		v->r = u;
    	}
    	u->pull();
    	v->pull();
    }
    void deal_with_push(node *v) {
    	static stack<node*> stk;
    	while (1) {
    		stk.push(v);
    		if (is_root(v)) {
    			break;
    		}
    		v = v->p;
    	}
    	while (!stk.empty()) {
    		stk.top()->push();
    		stk.pop();
    	}
    }
    void splay(node *v) {
    	deal_with_push(v);
    	while (!is_root(v)) {
    		node *u = v->p;
    		if (!is_root(u)) {
    			if ((v == u->l) ^ (u == u->p->l)) {
    				rotate(v);
    			} else {
    				rotate(u);
    			}
    		}
    		rotate(v);
    	}
    }
    void access(node *v) {
    	node *u = NULL;
    	while (v != NULL) {
    		splay(v);
    		v->r = u;
    		v->pull();
    		u = v;
    		v = v->p;
    	}
    }
    void make_root(node *v) {
    	access(v);
    	splay(v);
    	v->unsafe_reverse();
    }
    node* find_root(node *v) {
    	access(v);
    	splay(v);
    	while (v->l != NULL) {
    		v->push();
    		v = v->l;
    	}
    	splay(v);
    	return v;
    }
    void split(node *v, node *u) {
    	make_root(v);
    	access(u);
    	splay(u);
    }
    void link(node *v, node *u) {
    	if (find_root(v) == find_root(u)) {
    		return;
    	}
    	make_root(v);
    	v->p = u;
    }
    void cut(node *v, node *u) {
    	make_root(v);
    	if (find_root(u) == v && u->p == v && u->l == NULL) {
    		u->p = v->r = NULL;
    		v->pull();
    	}
    }
    
    int main() {
    	ios::sync_with_stdio(false);
    	cin.tie(0), cout.tie(0);
    	int n, m;
    	cin >> n >> m;
    	vector<node*> t(n + 1);
    	for (int i = 1, val; i <= n; i++) {
    		cin >> val;
    		t[i] = new node(val);
    	}
    	while (m--) {
    		int opt, x, y;
    		cin >> opt >> x >> y;
    		if (opt == 0) {
    			split(t[x], t[y]);
    			cout << t[y]->sum << endl;
    		}
    		if (opt == 1) {
    			link(t[x], t[y]);
    		}
    		if (opt == 2) {
    			cut(t[x], t[y]);
    		}
    		if (opt == 3) {
    			splay(t[x]);
    			t[x]->val = y;
    			t[x]->pull();
    		}
    	}
    	for (int i = 1; i <= n; i++) {
    		delete t[i];
    	}
    	return 0;
    }
    
  • 相关阅读:
    vue axios前端跨域问题
    DDD的神奇
    开源电子书《WoW C#》
    15项架构原则
    龙芯发布.NET 6.0.100开发者测试版
    国内 Mono 相关文章汇总
    Kubernetes应用程序开发认证(CKAD) 经验分享
    [LeetCode] 1281. Subtract the Product and Sum of Digits of an Integer 整数的各位积和之差
    我(webabcd)的文章索引
    上周热点回顾(1.31.9)
  • 原文地址:https://www.cnblogs.com/wzj-xhjbk/p/11546219.html
Copyright © 2020-2023  润新知